This version includes params_v2, which has the expanded number of zooplankton groups

Phase 1 Kappa starting point: use value of 10 t/km^2 from McCormack et al. 2020 to establish a steady model. Match model to time-averaged fishing (catch)

Phase 2 Then use historical FishMIP values to estimate the profile of the phytoplakton size spectrum

ACEAS data: Can we get empirical phytoplankton or zooplankton size spectra (BCG ARGO floats or particle counters) Jase Everett or ACEAS folks

Using pico (6.94559e-11) and large (6.06131e-07) phyto midpoints from Phoebe’s method as the assumed phytoplankton size range. ‘Spread’ the biomass estimate from McCormack of 10 t/km^2 across that size range and using Barnes equation to estimate the density at the intercept (density per gram at 0 on log scale): kappa = 17.9

Kappa for the whole model domain is 17.9 * 1.474341e+12 = 2.63907e+13

Setting kappa: How do we want to express the model domain. m^2 or the entire domain volume? Banzare Bank model domain is 1.474341e+12 [m^2]

Determine the size range for the phytoplankton from Stacey’s model - Make sure it’s density per

Can use historical fishMIP values to estimate the kappa value

https://github.com/pwoodworth-jefcoats/therMizer-FishMIP-2022-HI/blob/main/ClimateForcing/Plankton/Prep_Plankton_therMizer.Rmd * Double check all units to make sure they match * Size classes hard-coded so make sure to edit * time steps also hard-coded (need to adjust the arrays)

To get the starting point for Phoebe’s script, need a timeseries of total carbon density

Steady state is the base model (null hypothesis..) that fulfills the following criteria. It allows us to investigate change relative to the base model.

Clear rule for the model to represent endotherms

Within 25% biomass estimates

Realised PPMRs are consistent with empirical knowledge

Ontogenetic shifts

Unexploited size spectrum that is within ‘x’ of the expected by theory (definitely negative)

Sheldon biomass distribution = approx. 0

Emergent versus constrained

Production to biomass ratios - Ecopath estimates

trophic level comparison with ecopath models

Borrowing from other models, piecing the evidence together to allow us to explore the S&F of ecosystem with plankton to whales.

KEY QUESTIONS:

What are the emergent ecosystem properties, productivity, resilience etc,

How sensitive are ecosystem properties to perturbation of uncertain parameters (mesopelagic biomass, kappa etc)

Load libraries

remotes::install_github("sizespectrum/therMizer") # if needed
Skipping install of 'therMizer' from a github remote, the SHA1 (78ccfab0) has not changed since last install.
  Use `force = TRUE` to force installation
library(therMizer)
# remotes::install_github("sizespectrum/mizerExperimental")
# library(mizerExperimental)
# remotes::install_github("sizespectrum/mizerMR")
# library(mizer)
# library(mizerMR)
library(tidyverse)
# library(plotly)
# library(lhs)

Load group parameters

h values from data for some groups. Can try developing a model with them intitally, but it may require deleting all h values and proceeding from the beginning again with default caluclations from mizer using k_vb

k_vb_string <- c(0.4,0.3608333,0.1825,0.15,1,0.2,0.5,0.06,0.2,0.2,0.2,0.2,0.2,0.2,0.2) # to use all k_vb values and instead of h

# groups_raw <- read.csv("group params/trait_groups_params_vCWC.csv")
# groups_raw <- read.csv("group params/trait_groups_params_vCWC_v2.csv")
groups_raw <- read.csv("group params/trait_groups_params_vCWC_v2.csv")[,-1]
groups_raw

Fill in missing and adjust beta values for zooplankton groups using Heneghan et al. 2020 (10.1016/j.ecolmodel.2020.109265)

Need a value for microzooplankton microzooplankton (in McCormack et al. 2020) is composed of Heterotrophic dinoflagellates, tintinnids, ciliates, copepod nauplii Heneghan et al. log10PPMR values for: Hetero.Flagellates = 0.2–0.72 -> 0.46 Hetero.Ciliates = 2.5–2.9 -> 2.7 Mean: (2.7+0.46)/2 = 1.58 10^1.58 = 38.01894

Need to adjust values for mesozoo, other macrozoo, euphausiids, salps

Heneghan et al. log10PPMR values (midpoints for range) for: salps = 6.8–11.7 -> 9.25 10^9.25 = 1778279410

euphausiids = 6.6–7.8 -> 7.2 10^7.2 = 15848932

mesozoo (copepods) Omni.Cop. = 3.6–4.6 -> 4.1 Carn.Cop. = 0.8–1.9 -> 1.35 Mean: (4.1+1.35)/2 = 2.725 10^2.725 = 530.8844

other macrozoo () Chaetognaths = 1.9–3.4 -> 2.65 10^2.65 = 446.6836

groups_raw$beta[1] # microzooplantkon
[1] NA
groups_raw$beta[2] # mesozooplantkon, exisitng value of 500 is suitable
[1] 500
groups_raw$beta[3] # other macrozooplantkon, exisitng value of 500 is suitable
[1] 500
groups_raw$beta[4] # euphausiids 
[1] 500
groups_raw$beta[5] # salps
[1] 1000
groups_raw$beta[1] <- 38.01894 # microzooplantkon #groups_raw$beta[1] <- 38.01894 # microzooplantkon
# groups_raw$beta[2] # mesozooplantkon 
# groups_raw$beta[3] # other macrozooplantkon
groups_raw$beta[4] <- 15848932 # euphausiids
groups_raw$beta[5] <-  1778279410 # salps

groups_raw$beta[1] # microzooplantkon
[1] 38.01894
groups_raw$beta[2] # mesozooplantkon, exisitng value of 500 is suitable
[1] 500
groups_raw$beta[3] # other macrozooplantkon, exisitng value of 500 is suitable
[1] 500
groups_raw$beta[4] # euphausiids 
[1] 15848932
groups_raw$beta[5] # salps
[1] 1778279410
# groups_raw[,8] # confirm what column `h` is

groups_raw$h
 [1]  33.0  33.0  33.0  33.0  33.0    NA    NA    NA 189.0  66.0    NA    NA  33.0  38.5  41.0  18.0  18.0   5.2   8.3
h_update <- c(33.0,  33.0,  33.0,  33.0,  33.0,    NA,    NA,    NA, 189.0,  66.0,    NA,    NA,  NA,  NA,  NA,  NA,  NA,   NA,   NA)

groups_raw$h <- h_update

# groups_no_h <- groups_raw[,-8]

# groups_no_h$biomass_observed

# groups <- groups_no_h

k_vb_string <- c(0.6,0.4,0.4,0.4,0.4,0.3608333,0.1825,0.15,1,0.2,0.5,0.06,0.2,0.2,0.2,0.2,0.2,0.2,0.2) # to use all k_vb values and instead of h

groups_raw$k_vb <- k_vb_string
# groups$k_vb <- k_vb_string

# species_params <- groups

# species_params[6,4] #max size for small divers
# species_params[6,3] #maturation size
# species_params[6,2] #minimum size
# 
# species_params[6,3] <- 0.85*species_params[6,4]
# species_params[9,3] <- 0.99*species_params[9,4]
# 
# groups_raw[6,3] <- 0.85*groups_raw[6,4]
# groups_raw[9,3] <- 0.99*groups_raw[9,4]
length(groups_raw$species)
[1] 19
length(groups_raw$h)
[1] 19
length(groups_raw$k_vb)
[1] 19
groups_raw$h
 [1]  33  33  33  33  33  NA  NA  NA 189  66  NA  NA  NA  NA  NA  NA  NA  NA  NA
groups_raw$k_vb
 [1] 0.6000000 0.4000000 0.4000000 0.4000000 0.4000000 0.3608333 0.1825000 0.1500000 1.0000000 0.2000000 0.5000000 0.0600000 0.2000000 0.2000000
[15] 0.2000000 0.2000000 0.2000000 0.2000000 0.2000000
groups <- groups_raw

Update max and mat size for orca using sealifebase values rather than the previous w_max of 6t

groups$species[17]
[1] "orca"
groups$w_max[17]
[1] 6e+06
groups$w_mat[17]
[1] 4900000
groups$w_max[17] <- 10628034

groups$w_mat[17] <- 3198855

groups$w_max[17]
[1] 10628034
groups$w_mat[17]
[1] 3198855
groups$w_mat25[17]
NULL

Update max and mat size for leopard seal using sealifebase values. Max weight observed reported as 450kg. Using the sealifebase values for L-W conversion and max length results in an estimated max weight of 545875.2g, which is too high above the max weight observed.

groups$species[13]
[1] "leopard seals"
groups$w_max[13]
[1] 348000
groups$w_mat[13]
[1] 348000
groups$w_max[13] <- 450000
 
groups$w_max[13]
[1] 450000
groups$w_mat[13]
[1] 348000
groups$w_mat25[13]
NULL
groups[,7] # confirm what column `h` is
 [1]  33  33  33  33  33  NA  NA  NA 189  66  NA  NA  NA  NA  NA  NA  NA  NA  NA
# groups_no_h <- groups[,-7]
df_ind_CPUE <- readRDS("ind_catch_weight_BanzareBank_1930_2019_CPUE.rds")
df_CPUE_kg_day <- readRDS("catch_timeseries_BanzareBank_1930_2019_CPUE.rds")

glimpse(df_ind_CPUE)
Rows: 107,032
Columns: 9
Groups: Exp.no, Species [104]
$ ID          <int> 81681, 81687, 81689, 104868, 104869, 104879, 104881, 104886, 104907, 104908, 104909, 104910, 104916, 104921, 104959, 104960, 10496…
$ Exp.no      <int> 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781, 5781…
$ Year        <int> 1932, 1932, 1932, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933, 1933…
$ Species     <chr> "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Sperm", "Spe…
$ Length      <dbl> 1737.36, 1493.52, 1645.92, 1645.92, 1584.96, 1493.52, 1645.92, 1615.44, 1706.88, 1554.48, 1615.44, 1645.92, 1645.92, 1706.88, 1676…
$ Length.unit <int> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2…
$ Weight_kg   <dbl> 57160.49, 36312.79, 48601.83, 48601.83, 43399.17, 36312.79, 48601.83, 45951.43, 54204.52, 40943.21, 45951.43, 48601.83, 48601.83, …
$ date        <date> 1932-12-10, 1932-12-10, 1932-12-10, 1933-12-12, 1933-12-12, 1933-12-12, 1933-12-12, 1933-12-13, 1933-12-14, 1933-12-14, 1933-12-1…
$ Duration    <int> 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14…
glimpse(df_CPUE_kg_day)
Rows: 132
Columns: 5
Groups: Year [74]
$ Year           <int> 1930, 1931, 1932, 1932, 1933, 1933, 1934, 1934, 1935, 1935, 1936, 1936, 1937, 1937, 1938, 1938, 1939, 1939, 1940, 1940, 1946, 1…
$ Species        <chr> "Baleen", "Baleen", "Baleen", "Sperm", "Baleen", "Sperm", "Baleen", "Sperm", "Baleen", "Sperm", "Baleen", "Sperm", "Baleen", "S…
$ total_catch_kg <dbl> 50155688.1, 335374080.1, 306611735.0, 142075.1, 496515326.7, 3108915.8, 279492543.5, 5993267.0, 220991003.5, 3701391.0, 1845312…
$ effort_days    <dbl> 79.5265942, 373.4554741, 260.8692295, 0.7931792, 471.8601991, 16.4294765, 309.9332648, 26.8628395, 241.8924453, 18.4724967, 211…
$ CPUE           <dbl> 630678.2, 898029.6, 1175346.5, 179121.1, 1052250.9, 189227.9, 901783.0, 223106.2, 913592.0, 200373.1, 870732.1, 219485.6, 91067…

Yield for the period that matches Ecopath model, post 2000 annual average

df_yield_2000_2019 <- df_CPUE_kg_day %>% 
  filter(Year > 2000) %>% 
  group_by(Species) %>% 
  summarise(yield = sum(total_catch_kg)/19)

df_yield_2000_2019

Add yield in tonnes per km2, same as g m2 and it is consistent with biomass_observed

1.474341e+12 m^2 for model domain

1.474341e+12/1e+6 = 1474341 km^2

507511 kg of minke whale per year from 2000 - 2019

507.5/1474341 = 0.0003442216 tonnes Minke whale yield per km2 from 2000 - 2019

15619.24 kg of baleen whale per year from 2000 - 2019

15.6/1474341 = 1.0581e-05 tonnes of baleen whale per km2 from 2000 - 2019

yield_observed <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0003442216, 0, 0, 1.0581e-05) # to add a yield_observed column in species_params

groups$yield_observed <- yield_observed
biomass_cutoff <- c(0, 0, 0, 0.1, 0.1, 1, 1, 1, 40, 4500, 1, 1, 200000, 10000, 135000, 600000, 490000, 3650000, 2250000) # to add a biomass_cutoff column in species_params

groups$biomass_cutoff <- biomass_cutoff
groups |> dplyr::select(species, yield_observed, biomass_observed, biomass_cutoff, w_min)
groups_final <- groups[-c(1:3),]

groups_final

Run a range of models to different biomass estimates Use an ensemble approach Perturbation to test the change in size structure and functions

Load interaction matrix

theta <- readRDS("trait_groups_interaction_matrix_vCWC_v2.RDS")
theta

Interaction between orca should be 0, so this needs to be adjusted from original

# theta[13,13]
theta[17,17]
[1] 1
theta[17,17] <- 0

theta[17,17]
[1] 0
theta_final <- theta[-(1:3),-(1:3)]

theta_final

Adding min and max temp for each group

Using sealifebase for all non-fish species/groups. In most cases, there are no listed Temperature values in the ‘Environment’ section, like there is for more data-rich species, e.g., cod

Instead, there are values at the bottom of the sealifebase pages in ‘Estimates of some properties based on models’ with ‘Preferred temperature’ estimates from the AquaMaps model-based approach (https://www.gbif.org/tool/81356/aquamaps-predicted-range-maps-for-aquatic-species)

[1] “euphausiids”: Antarctic krill - (Preferred temperature (Ref. 115969): -1.5 - 1.6, mean 0.2 (based on 535 cells)) Crystal krill - (Preferred temperature (Ref. 115969): -1.8 - 1.1, mean -1.6 (based on 3588 cells)) Thysanoessa macrura - (Preferred temperature (Ref. 115969): -1.2 - 2.8, mean 0.2 (based on 24 cells). Not included due to small number of cells and low contribution to biomass in this model domain [2]“mesopelagic fishes” - Electrona antarctica(nothing on fishbase)
[3]“bathypelagic fishes”
[4]“shelf and coastal fishes”: Marbled rockcod (-1 - 5) [5]“flying birds”: Southern giant petrel (Preferred temperature (Ref. 115969): 2.1 - 15.6, mean 10.1 (based on 533 cells)); Arctic tern (Sterna paradisaea) (Preferred temperature (Ref. 115969): 0.4 - 13.3, mean 6.8 (based on 2468 cells)) Thalassarche chrysostoma (Grey-headed petrel) (Preferred temperature (Ref. 115969): 1.3 - 9.1, mean 5.2 (based on 263 cells)) South polar skua (Preferred temperature (Ref. 115969): 0.2 - 18.2, mean 6.4 (based on 1318 cells)) Diomedea exulans (Wandering albatross), (Preferred temperature (Ref. 115969): 0.5 - 12, mean 4.6 (based on 1528 cells)_ [6]“small divers” - no info for adelie, gentoo or crested penguins on sealifebase. Guess based on medium divers
[7]“squids” - based on Psychroteuthis glacialis (sealifebase)
[8]“toothfishes” - no data on fishbase
[9]“leopard seals” - Preferred temperature (Ref. 115969): -1.9 - 1.4, mean -0.5 (based on 2109 cells).
[10] “medium divers”: Crabeater Seals - (Preferred temperature (Ref. 115969): -0.4 - 1, mean 0.1 (based on 9397 cells)) Ross seals (Preferred temperature (Ref. 115969): -1.8 - 1.1, mean -1.5 (based on 2110 cells)); Weddell seals (Preferred temperature (Ref. 115969): -1.8 - 1, mean -1.6 (based on 6026 cells)); Hourglass dolphin (Preferred temperature (Ref. 115969): 0.1 - 2, mean 0.9 (based on 11222 cells)) # Not included in the biomass King penguin (no data on sealifebase) Emperor penguin (no data on sealifebase) [11]“large divers” - Southern elephant seals only in this group now that Sperm whales are also seperated
[12]“minke whales”
[13]“orca”
[14]“sperm whales”
[15]“baleen whales”

groups_final$temp_min <- c(-1.8, # euphausiids
                           -2, # salps
                                     -2, # mesopelagic fishes
                                     -2, # bathypelagic fishes
                                     -1, # "shelf and coastal fishes" 
                                     0.2, # "flying birds"
                                     -0.4, # "small divers"             
                                     -0.8, # "squids"                  
                                     -2, # "toothfishes"              
                                     -1.9, # "leopard seals"           
                                     -0.4, # "medium divers"            
                                     0.1, # "large divers"             
                                     0.2, # "minke whales"             
                                     0.3, # "orca"                     
                                     0.3, # "sperm whales"             
                                     0.2) # "baleen whales"

groups_final$temp_max <- c(1.6, # euphausiids
                           5, #salps
                                     5, # mesopelagic fishes
                                     5, # bathypelagic fishes
                                     5, # "shelf and coastal fishes" 
                                     18.2, # "flying birds"
                                     1, # "small divers"             
                                     1.1, # "squids"                  
                                     5, # "toothfishes"              
                                     1.4, # "leopard seals"           
                                     1, # "medium divers"            
                                     1.6, # "large divers"             
                                     7, # "minke whales"             
                                     13.1, # "orca"                     
                                     3.8, # "sperm whales"             
                                     10.2) # "baleen whales"
glimpse(groups_final)
Rows: 16
Columns: 17
$ species             <chr> "euphausiids", "salps", "mesopelagic fishes", "bathypelagic fishes", "shelf and coastal fishes", "flying birds", "small di…
$ w_min               <dbl> 6.309573e-05, 3.162278e-05, 1.000000e-03, 6.969100e-04, 3.591364e-03, 4.000000e+01, 4.500000e+03, 3.591364e-03, 3.351032e-…
$ w_mat               <dbl> 1.584893e-02, 2.511886e-01, 1.127500e+01, 6.255000e+01, 4.675000e+01, 1.718542e+03, 4.266667e+03, 1.280543e+02, 1.276520e+…
$ w_max               <dbl> 3.162278e+00, 2.511886e+01, 2.400000e+02, 6.037000e+02, 2.422200e+03, 4.191250e+03, 6.000000e+03, 2.071835e+04, 1.575693e+…
$ beta                <dbl> 1.584893e+07, 1.778279e+09, 4.416667e+02, 4.250000e+02, 3.500000e+02, 5.813503e+01, 2.937879e+02, 5.000000e+01, 1.000000e+…
$ k_vb                <dbl> 0.4000000, 0.4000000, 0.3608333, 0.1825000, 0.1500000, 1.0000000, 0.2000000, 0.5000000, 0.0600000, 0.2000000, 0.2000000, 0…
$ h                   <dbl> 33, 33, NA, NA, NA, 189, 66, NA, NA, NA, NA, NA, NA, NA, NA, NA
$ min_depth           <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ max_depth           <int> 3500, 500, 5300, 4000, 728, 10, 100, 2000, 3850, 100, 1500, 1500, 50, 200, 2000, 200
$ water.column.use    <chr> "non DVM", "non DVM", "DVM", "DVM", "ontogenetic", "diving", "diving", "non DVM", "non DVM", "diving", "diving", "diving",…
$ p_time_prydz        <dbl> 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.387500, 0.610000, 1.000000, 1.000000, 0.750000, 0.535625, 0.330000, 0.…
$ pc_annual_offspring <dbl> NA, NA, NA, NA, NA, 0.5, 0.6, NA, NA, 0.5, 0.6, 0.5, 0.5, 0.5, 0.5, 0.5
$ biomass_observed    <dbl> 5.900, 0.652, 1.200, 1.930, 0.802, 0.003, 0.016, 0.150, 0.750, 0.002, 0.265, 0.022, 0.014, 0.006, 0.011, 0.127
$ yield_observed      <dbl> 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.00000000…
$ biomass_cutoff      <dbl> 1.00e-01, 1.00e-01, 1.00e+00, 1.00e+00, 1.00e+00, 4.00e+01, 4.50e+03, 1.00e+00, 1.00e+00, 2.00e+05, 1.00e+04, 1.35e+05, 6.…
$ temp_min            <dbl> -1.8, -2.0, -2.0, -2.0, -1.0, 0.2, -0.4, -0.8, -2.0, -1.9, -0.4, 0.1, 0.2, 0.3, 0.3, 0.2
$ temp_max            <dbl> 1.6, 5.0, 5.0, 5.0, 5.0, 18.2, 1.0, 1.1, 5.0, 1.4, 1.0, 1.6, 7.0, 13.1, 3.8, 10.2
head(groups_final)

Create params to get w values

params <- newMultispeciesParams(species_params = groups_final, 
                                interaction = theta_final, 
                                kappa = 10,
                                w_pp_cutoff = 100,
                                min_w_pp = 1e-14)
For the species large divers, minke whales, sperm whales the value for `w_mat` is not smaller than that of `w_max`. I have corrected that by setting it to about 25% of `w_mat.
For the species small divers the value for `w_min` is not smaller than that of `w_mat`. I have reduced the values.
Because you have n != p, the default value for `h` is not very good.
Because the age at maturity is not known, I need to fall back to using von Bertalanffy parameters, where available, and this is not
reliable.
No ks column so calculating from critical feeding level.
Using z0 = z0pre * w_max ^ z0exp for missing z0 values.
Using f0, h, lambda, kappa and the predation kernel to calculate gamma.
saveRDS(params, "base_params.rds")

Set up time steps:

time_steps <- seq(0,600,1)
# I ran into trouble using any time steps that didn't start with 0.
# I also had trouble using fractional time steps.  
# So, what's here as year is really a month.  
# Suggestions for a better solution welcome

Set up the resource:

# Fill array
# Need an extra time step preceding the simulation
n_pp_array[1,] <- isimip_plankton[1,]
Error in n_pp_array[1, ] <- isimip_plankton[1, ] : 
  number of items to replace is not a multiple of replacement length

Set up temperature-related information:

# # Load ocean temp array
# # Note: You may need to update this path
# ocean_temp <- read.table("ClimateForcing/GFDL_ocean_temp_realm_array.dat")
# ocean_temp <- as(ocean_temp, "matrix")
# r <- colnames(ocean_temp)
# ocean_temp_array <- array(NA, dim = c(length(time_steps), length(r)), dimnames = list(time = time_steps, realm_names = r))
# ocean_temp_array[1,] <- ocean_temp[1,]
# for (t in seq(1,length(time_steps) - 1, 1)) {
#   ocean_temp_array[t + 1,] <- ocean_temp[t,]
# }

Now we will set up the vertical_migration array. We’ll assume that:

groups_VMA <- groups_final

realm_names <- c("upper50m","bottom","DVM_day","DVM_night","ontogenetic","diving")
species_names <- as.character(groups_VMA$species)
sizes <- params@w

# Create the vertical migration array and fill it
vertical_migration_array <- array(0, dim = (c(length(realm_names), 
                                  length(species_names), length(sizes))), 
                                  dimnames = list(realm = realm_names, sp = species_names, 
                                  w = signif(sizes,3))) # realm x species x size

upp <- which(realm_names == "upper50m") # 0 - 50m average
btm <- which(realm_names == "bottom") # sea floor
DVMd <- which(realm_names == "DVM_day") # 200 - 500m average
DVMn <- which(realm_names == "DVM_night") # 0 - 100m average
ont <- which(realm_names == "ontogenetic") # deeper after w_mat
dive <- which(realm_names == "diving") # evenly spread across entire realm

# Set all sizes below w_mat for euphausiids to "upper50m" and all sizes above w_mat to "bottom
spA <- which(species_names == "euphausiids")
vertical_migration_array[upp, spA, sizes < params@species_params$w_mat[spA]] <- 1
vertical_migration_array[btm, spA, sizes >= params@species_params$w_mat[spA]] <- 1

# Set all sizes below w_mat for euphausiids to "upper50m" and all sizes above w_mat to "bottom
spS <- which(species_names == "salps")
vertical_migration_array[DVMd, spS, ] <- 0.5
vertical_migration_array[DVMn, spS, ] <- 0.5

# Have mesopelagic fishes split its time equally using DVM
spB <- which(species_names == "mesopelagic fishes")
vertical_migration_array[DVMd, spB, ] <- 0.5
vertical_migration_array[DVMn, spB, ] <- 0.5

# Set all sizes below w_mat for bathypelagic fishes to "upper50m" and split time equally using DVM for sizes above w_mat
spC <- which(species_names == "bathypelagic fishes")
vertical_migration_array[upp, spC, sizes < params@species_params$w_mat[spC]] <- 1
vertical_migration_array[DVMd, spC, sizes >= params@species_params$w_mat[spC]] <- 0.5
vertical_migration_array[DVMn, spC, sizes >= params@species_params$w_mat[spC]] <- 0.5

# Set all sizes below w_mat for shelf and coastal fishes to "upper50m" and all sizes above w_mat to "bottom"
spD <- which(species_names == "shelf and coastal fishes")
vertical_migration_array[upp, spD, sizes < params@species_params$w_mat[spD]] <- 1
vertical_migration_array[btm, spD, sizes >= params@species_params$w_mat[spD]] <- 1

# Have flying birds spend all their time in "diving"
spE <- which(species_names == "flying birds")
vertical_migration_array[dive, spE, ] <- 1

# Have small divers spend all their time in "diving"
spF <- which(species_names == "small divers")
vertical_migration_array[dive, spF, ] <- 1

# Set all sizes below w_mat for squids to "upper50m" and split time equally using DVM for sizes above w_mat
spG <- which(species_names == "squids")
vertical_migration_array[upp, spG, sizes < params@species_params$w_mat[spG]] <- 1
vertical_migration_array[DVMd, spG, sizes >= params@species_params$w_mat[spG]] <- 0.5
vertical_migration_array[DVMn, spG, sizes >= params@species_params$w_mat[spG]] <- 0.5

# Set all sizes below w_mat for toothfishes to "upper50m" and all sizes above w_mat to "bottom
spH <- which(species_names == "toothfishes")
vertical_migration_array[upp, spH, sizes < params@species_params$w_mat[spH]] <- 1
vertical_migration_array[btm, spH, sizes >= params@species_params$w_mat[spH]] <- 1

# Have leopard seals spend all their time in "diving"
spI <- which(species_names == "leopard seals")
vertical_migration_array[dive, spI, ] <- 1

# Have medium divers spend all their time in "diving"
spJ <- which(species_names == "medium divers")
vertical_migration_array[dive, spJ, ] <- 1

# Have large divers spend all their time in "diving"
spK <- which(species_names == "large divers")
vertical_migration_array[dive, spK, ] <- 1

# Have minke whales spend all their time in "diving"
spL <- which(species_names == "minke whales")
vertical_migration_array[dive, spL, ] <- 1

# Have orca spend all their time in "diving"
spM <- which(species_names == "orca")
vertical_migration_array[dive, spM, ] <- 1

# Have sperm whales spend all their time in "diving"
spN <- which(species_names == "sperm whales")
vertical_migration_array[dive, spN, ] <- 1

# Have baleen whales spend all their time in "diving"
spO <- which(species_names == "baleen whales")
vertical_migration_array[dive, spO, ] <- 1

Using the same scenario, everything is present in all layers, so the exposure array is all 1s.

exposure_array <- array(1, dim = (c(length(realm_names),
                                    length(species_names))), 
                        dimnames = list (realm = realm_names, sp = species_names)) #realm x species

exposure_array
             sp
realm         euphausiids salps mesopelagic fishes bathypelagic fishes shelf and coastal fishes flying birds small divers squids toothfishes
  upper50m              1     1                  1                   1                        1            1            1      1           1
  bottom                1     1                  1                   1                        1            1            1      1           1
  DVM_day               1     1                  1                   1                        1            1            1      1           1
  DVM_night             1     1                  1                   1                        1            1            1      1           1
  ontogenetic           1     1                  1                   1                        1            1            1      1           1
  diving                1     1                  1                   1                        1            1            1      1           1
             sp
realm         leopard seals medium divers large divers minke whales orca sperm whales baleen whales
  upper50m                1             1            1            1    1            1             1
  bottom                  1             1            1            1    1            1             1
  DVM_day                 1             1            1            1    1            1             1
  DVM_night               1             1            1            1    1            1             1
  ontogenetic             1             1            1            1    1            1             1
  diving                  1             1            1            1    1            1             1

Create the temperatures for each realm.

# Create temperature array and fill it
times <- 0:500
ocean_temp_array <- array(NA, dim = c(length(times), length(realm_names)), 
                    dimnames = list(time = times, realm = realm_names))
temp_inc <- 0
for (i in 1:501) {
  ocean_temp_array[i,] <- c(2 + temp_inc, -2 + temp_inc, 2 + temp_inc, -1 + temp_inc, -1 + temp_inc, -1 + temp_inc)
  temp_inc <- temp_inc + 0.01
}

Create a dynamic, time-varying resource spectra.


x <- params@w_full
slope <- -1
intercept <- -5

# Create resource array and fill it
n_pp_array <- array(NA, dim = c(length(times), length(x)), 
                    dimnames = list(time = times, w = signif(x,3)))

for (i in 1:501) {
  # Add some noise around the slope and intercept as we fill the array
  n_pp_array[i,] <- (slope * runif(1, min = 0.95, max = 1.05) * log10(x)) + 
                    (intercept * runif(1, min = 0.95, max = 1.05))
}

Running a scenario

The upgradeTherParams function combines a standard mizerParams object with the therMizer objects described above.

so_therm_model <-  upgradeTherParams(params, 
                            # temp_min = temp_min,
                            # temp_max = temp_max,
                            ocean_temp_array = ocean_temp_array,
                            n_pp_array = n_pp_array, 
                            vertical_migration_array = vertical_migration_array,
                            exposure_array = exposure_array, 
                            aerobic_effect = TRUE, 
                            metabolism_effect = TRUE)
Warning: The dimnames of the second dimension of n_pp_array are not the same
      as the ones in w_full. Since the dimension size is the same, the dimnames
      have been replaced by w_full.
                                

Let’s look at the thermal tolerances of all the species in the model.

params_v00 <- steady(so_therm_model)
Warning: euphausiids, flying birds, small divers, squids, leopard seals, medium divers, large divers, minke whales, orca, sperm whales, baleen whales are going extinct.Simulation run did not converge after 1.5 years. Value returned by the distance function was: NA
Error in setBevertonHolt(params, reproduction_level = old_reproduction_level) : 
  Some species have no reproduction.
box.params <- so_therm_model

box.params@species_params$ppmr_min[box.params@species_params$species == "baleen whales"]  <- 1e5
box.params@species_params$ppmr_max[box.params@species_params$species == "baleen whales"] <-5e7
box.params@species_params$pred_kernel_type[box.params@species_params$species == "baleen whales"] <- "box"
species_params(box.params) |> dplyr::select(w_min, w_mat, w_max)

Adjust w_mat values that were changed by default in newMultispeciesParams

params_v1 <- box.params

params_v1@species_params$w_mat[params_v1@species_params$species == "large divers"]  <- params_v1@species_params$w_max[params_v1@species_params$species == "large divers"] * 0.9
params_v1@species_params$w_mat[params_v1@species_params$species == "minke whales"]  <- params_v1@species_params$w_max[params_v1@species_params$species == "minke whales"] * 0.9
params_v1@species_params$w_mat[params_v1@species_params$species == "orca"]  <- params_v1@species_params$w_max[params_v1@species_params$species == "orca"] * 0.9
params_v1@species_params$w_mat[params_v1@species_params$species == "sperm whales"]  <- params_v1@species_params$w_max[params_v1@species_params$species == "sperm whales"] * 0.9

params_v1 <- setParams(params_v1)
params_v2 <- params_v1

params_v2@species_params$w_min[params_v2@species_params$species == "small divers"]  <- params_v2@species_params$w_mat[params_v2@species_params$species == "small divers"] * 0.85
params_v2@species_params$w_min[params_v2@species_params$species == "leopard seals"]  <- params_v2@species_params$w_mat[params_v2@species_params$species == "leopard seals"] * 0.85

params_v2 <- setParams(params_v2)

First simulation using raw param values Need to adjust starting Rmax values. Use Julia’s quick calibration using kappa (although starting kappa is a total guess as well)

params_guessed <- params_v2

params_guessed@species_params$R_max <- params_guessed@resource_params$kappa*params_guessed@species_params$w_max^-1.5

params_guessed <- setParams(params_guessed)

sim_guessed <- project(params_guessed, effort=0)

[=>------------------------------------------]   4% ETA:  9s
[=>------------------------------------------]   5% ETA:  8s
[==>-----------------------------------------]   6% ETA:  8s
[==>-----------------------------------------]   7% ETA:  9s
[==>-----------------------------------------]   8% ETA:  9s
[===>----------------------------------------]   9% ETA:  8s
[===>----------------------------------------]  10% ETA:  8s
[====>---------------------------------------]  11% ETA:  9s
[====>---------------------------------------]  12% ETA:  8s
[=====>--------------------------------------]  13% ETA:  8s
[=====>--------------------------------------]  14% ETA:  8s
[======>-------------------------------------]  15% ETA:  8s
[======>-------------------------------------]  16% ETA:  8s
[======>-------------------------------------]  17% ETA:  7s
[=======>------------------------------------]  18% ETA:  7s
[=======>------------------------------------]  19% ETA:  8s
[========>-----------------------------------]  20% ETA:  7s
[========>-----------------------------------]  21% ETA:  7s
[=========>----------------------------------]  22% ETA:  7s
[=========>----------------------------------]  23% ETA:  7s
[=========>----------------------------------]  24% ETA:  7s
[==========>---------------------------------]  25% ETA:  7s
[==========>---------------------------------]  26% ETA:  7s
[===========>--------------------------------]  27% ETA:  7s
[===========>--------------------------------]  28% ETA:  7s
[============>-------------------------------]  29% ETA:  7s
[============>-------------------------------]  30% ETA:  6s
[=============>------------------------------]  31% ETA:  7s
[=============>------------------------------]  32% ETA:  6s
[=============>------------------------------]  33% ETA:  6s
[==============>-----------------------------]  34% ETA:  6s
[==============>-----------------------------]  35% ETA:  6s
[===============>----------------------------]  36% ETA:  6s
[===============>----------------------------]  37% ETA:  6s
[================>---------------------------]  38% ETA:  6s
[================>---------------------------]  39% ETA:  6s
[================>---------------------------]  40% ETA:  6s
[=================>--------------------------]  41% ETA:  5s
[=================>--------------------------]  42% ETA:  5s
[==================>-------------------------]  43% ETA:  5s
[==================>-------------------------]  44% ETA:  5s
[===================>------------------------]  45% ETA:  5s
[===================>------------------------]  46% ETA:  5s
[===================>------------------------]  47% ETA:  5s
[====================>-----------------------]  48% ETA:  5s
[====================>-----------------------]  49% ETA:  5s
[=====================>----------------------]  50% ETA:  5s
[======================>---------------------]  51% ETA:  4s
[======================>---------------------]  52% ETA:  4s
[=======================>--------------------]  53% ETA:  4s
[=======================>--------------------]  54% ETA:  4s
[=======================>--------------------]  55% ETA:  4s
[========================>-------------------]  56% ETA:  4s
[========================>-------------------]  57% ETA:  4s
[=========================>------------------]  58% ETA:  4s
[=========================>------------------]  59% ETA:  4s
[==========================>-----------------]  60% ETA:  4s
[==========================>-----------------]  61% ETA:  4s
[==========================>-----------------]  62% ETA:  3s
[===========================>----------------]  63% ETA:  3s
[===========================>----------------]  64% ETA:  3s
[============================>---------------]  65% ETA:  3s
[============================>---------------]  66% ETA:  3s
[=============================>--------------]  67% ETA:  3s
[=============================>--------------]  68% ETA:  3s
[=============================>--------------]  69% ETA:  3s
[==============================>-------------]  70% ETA:  3s
[==============================>-------------]  71% ETA:  3s
[===============================>------------]  72% ETA:  3s
[===============================>------------]  73% ETA:  3s
[================================>-----------]  74% ETA:  2s
[================================>-----------]  75% ETA:  2s
[=================================>----------]  76% ETA:  2s
[=================================>----------]  77% ETA:  2s
[=================================>----------]  78% ETA:  2s
[==================================>---------]  79% ETA:  2s
[==================================>---------]  80% ETA:  2s
[===================================>--------]  81% ETA:  2s
[===================================>--------]  82% ETA:  2s
[====================================>-------]  83% ETA:  2s
[====================================>-------]  84% ETA:  1s
[====================================>-------]  85% ETA:  1s
[=====================================>------]  86% ETA:  1s
[=====================================>------]  87% ETA:  1s
[======================================>-----]  88% ETA:  1s
[======================================>-----]  89% ETA:  1s
[=======================================>----]  90% ETA:  1s
[=======================================>----]  91% ETA:  1s
[========================================>---]  92% ETA:  1s
[========================================>---]  93% ETA:  1s
[========================================>---]  94% ETA:  1s
[=========================================>--]  95% ETA:  0s
[=========================================>--]  96% ETA:  0s
[==========================================>-]  97% ETA:  0s
[==========================================>-]  98% ETA:  0s
[===========================================>]  99% ETA:  0s
plot(sim_guessed)

plotlyFeedingLevel(sim_guessed)
plotlyBiomass(sim_guessed)
# plotDiet(sim_guessed)
plotSpectra(sim_guessed)

Apex predators have the most diverse diet and are only preying upon dynamic groups. However, this means they don’t have enough to eat. We can either open up resources available to them, although the empirical observations suggest that they should be eating the larger inviduals of groups like divers. So, instead of increasing beta or increasing the width of their feeding kernel, we will try to add a new resource spectrum that only apex predators can access to aid their growth and reproduction. If we can reach a steady state in this fashion, then we can remove the additional resource with further calibration efforts.

params_v00 <- steady(params_guessed)
Warning: euphausiids, flying birds, small divers, squids, leopard seals, medium divers, large divers, minke whales, orca, sperm whales, baleen whales are going extinct.Simulation run did not converge after 1.5 years. Value returned by the distance function was: NA
Error in setBevertonHolt(params, reproduction_level = old_reproduction_level) : 
  Some species have no reproduction.
library(mizerExperimental)
params_g_v2 <- mizerExperimental::scaleDownBackground(params_guessed,100000)
Error in setBevertonHolt(params, reproduction_level = 1/4) : 
  Some species have no reproduction.
params_guessed <- params_guessed

params_guessed@species_params$beta[box.params@species_params$species == "orca"]  <- 100
# params_guessed@species_params$sigma[box.params@species_params$species == "orca"] <- 2.5
params_v00 <- steady(params_guessed)
Warning: euphausiids, flying birds, small divers, squids, leopard seals, medium divers, large divers, minke whales, orca, sperm whales, baleen whales are going extinct.Simulation run did not converge after 1.5 years. Value returned by the distance function was: NA
Error in setBevertonHolt(params, reproduction_level = old_reproduction_level) : 
  Some species have no reproduction.
params_tuned_v1 <- mizerExperimental::tuneParams(params_guessed)

Listening on http://127.0.0.1:6508
Warning: In sliderInput(): `value` should be greater than or equal to `min` (value = 0.0158489319246111, min = 1).Warning: In sliderInput(): `value` should be greater than or equal to `min` (value = 0.0158489319246111, min = 1).Warning: Removed 11 rows containing missing values (`position_stack()`).  3: shiny::runApp
  2: runGadget
  1: mizerExperimental::tuneParams
NA

params_guessed@species_params$species
params_guessed@species_params$R_max


params_v1 <- params_guessed

# params_v1@species_params$R_max[params_v1@species_params$species == "orca"] <- Inf

# params_v1@species_params$gamma[params_v1@species_params$species == "orca"] <- params_v1@species_params$gamma[params_v1@species_params$species == "orca"] * 50

# params_v1@species_params$gamma[params_v1@species_params$species == "microzooplankton"] <- params_v1@species_params$gamma[params_v1@species_params$species == "microzooplankton"] * 2

params_v1@species_params$gamma[params_v1@species_params$species == "flying birds"] <- params_v1@species_params$gamma[params_v1@species_params$species == "flying birds"] * 2
params_steady_v1 <- steady(params_tuned_v1)
Warning: euphausiids, salps, mesopelagic fishes, bathypelagic fishes, shelf and coastal fishes, flying birds, squids, toothfishes, medium divers, large divers, minke whales, orca, sperm whales, baleen whales are going extinct.Simulation run did not converge after 1.5 years. Value returned by the distance function was: NA
Error in if (any(resource_rate[mu != 0] == 0)) { : 
  missing value where TRUE/FALSE needed

Refine box feeding kernel for the baleen whales max ppmr value are based on w_max baleen whale feeding on w_min euphausiids min ppmr value based on w_min baleen whale feeding on w_max euphausiids

params_v2 <- params_v1

params_v2@species_params$w_min[params_v2@species_params$species == "baleen whales"]
params_v2@species_params$w_max[params_v2@species_params$species == "baleen whales"]

params_v2@species_params$w_min[params_v2@species_params$species == "euphausiids"]
params_v2@species_params$w_max[params_v2@species_params$species == "euphausiids"]
# 1.03e+08/6.31e-05 # w_max baleen whale divided by w_min euphausiids
# 2250000/3.162278 # w_min baleen whale divided by w_max euphausiids

params_v2@species_params$ppmr_min[params_v2@species_params$species == "baleen whales"]  <- 711512.4
params_v2@species_params$ppmr_max[params_v2@species_params$species == "baleen whales"] <- 1.63233e+12

# params_v2@species_params$ppmr_min[params_v2@species_params$species == "baleen whales"]  <- 1e5
# params_v2@species_params$ppmr_max[params_v2@species_params$species == "baleen whales"] <-5e7
params_v2@species_params$pred_kernel_type[params_v2@species_params$species == "baleen whales"] <- "box"
params_v2 <- setParams(params_v2)

sim_v2 <- project(params_v2, effort=0, t_max = 500)

plot(sim_v2)
params_tuned <- tuneGrowth(params_v2)
mizer::plotDiet(params_v2)
# saveRDS(params_v2, "stage1_steady.rds") #stage 1 is with baleen whale box kernel, adjusted maturation sizes for most marine mammals and a background resource with a large max size

params_v2 <- readRDS("stage1_steady.rds")

Now I will try to reduce the max size of the resource

params_v3 <- params_v2

params_v3@resource_params$w_pp_cutoff # started with 10000

params_v3@resource_params$w_pp_cutoff  <- 100
params_v3 <- setParams(params_v3)

sim_v3 <- project(params_v3, effort=0, t_max = 1000)

plot(sim_v3)
mizer::plotDiet(params_v3)
params_v3_steady <- steady(params_v3)
params_v3_tuned <- tuneParams(params_v3_steady)
params_v3_tuned@species_params$erepro
params_v3_tuned@species_params$w_mat
params_v3_tuned@species_params$w_mat25
params_v3_tuned@resource_params$w_pp_cutoff
mizer::plotDiet(params_v3_tuned)
params_v4 <- tuneGrowth(params_v3_tuned)

sim_v4 <- project(params_v4, effort=0, t_max = 1000)

plot(sim_v4)
plotlyBiomass(sim_v4)
params_v5 <- tuneGrowth(params_v4)

sim_v5 <- project(params_v5, effort=0, t_max = 1000)

plot(sim_v5)
plotlyBiomass(sim_v5)
params_v5_steady <- steady(params_v5)
params_v5_tuned <- tuneParams(params_v5_steady)
# params_v6 <- setParams(params_v5_tuned)

sim_v6 <- project(params_v5_tuned, effort=0, t_max = 2000)

plot(sim_v6)
plotlyBiomass(sim_v6)
params_v6 <- steady(params_v5_tuned)

plotBiomassVsSpecies(params_v6)
plotlySpectra(params_v6, power = 2)

params_v6 <- calibrateBiomass(params_v6)
plotBiomassVsSpecies(params_v6)
params_v7 <- params_v6 |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady()
sim_v7 <- project(params_v7, effort=0, t_max = 1000)

plot(sim_v7)
plotlyBiomass(sim_v7)
mizer::plotDiet(params_v7)
params_v8 <- tuneGrowth(params_v7)
params_v9 <- steady(params_v8, t_max = 1000)
sim_v8 <- project(params_v9, effort=0, t_max = 1000)

plot(sim_v8)
plotlyBiomass(sim_v8)
params_v9@species_params$erepro
params_v9@species_params$erepro

cm <- params_v9
cm <- setBevertonHolt(cm, erepro = c(0.006539088, 0.008324580, 0.017341896, 0.011144187, 0.003926176, 0.235560686, 0.010509550, 0.052390073, 0.205232541, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2))
species_params(cm) |> select(erepro, R_max)

cm_v1 <- steady(cm)
sim_cm_v1 <- project(cm_v1, effort=0, t_max = 2000)

plot(sim_cm_v1)
plotlyBiomass(sim_cm_v1)
plotlySpectra(sim_cm_v1, power=1)
kappa <-  resource_params(cm_v1)$kappa
lambda <- resource_params(cm_v1)$lambda
w_max <- 100 
w_full(cm_v1)[[1]]
w_min <- 1e-12

Now we put all these resource parameters into a data frame.

SO_resource_params <-  data.frame(
    resource = c("pl"),
    lambda = c(lambda),
    kappa = c(kappa),
    w_min = c(w_min),
    w_max = c(w_max)
)

SO_resource_params
params_pl_rs <- cm_v1
resource_params(params_pl_rs) <- SO_resource_params
# params_pparams_pl_rsl_rs <- setParams(params_pl_rs)

sim_v_pl_rs <- project(params_pl_rs, effort=0, t_max = 1000)

plot(sim_v_pl_rs)
mizer::plotDiet(params_pl_rs)
mizer::plotDiet(params_v4)
params <- readRDS("tuned_params.rds")

params <- steady(params)

Check the spectra

plotlySpectra(params, power = 2)
plotBiomassVsSpecies(params)
params <- calibrateBiomass(params)
plotBiomassVsSpecies(params)
plotlySpectra(params)

Rescale species spectra

params <- matchBiomasses(params)
plotBiomassVsSpecies(params)

Can add upper and lower boundaries for observed biomass range

params_v3 <- tuneParams(params)
plotlySpectra(params_v3)

sim <- project(params_v3, effort = 0 , t_max = 500)

plot(sim)
params_v4 <- tuneParams(params_v3)
params_v5 <- tuneGrowth(params_v4)
params_v6 <- tuneParams(params_v5)

# saveRDS(params_v6, "phase1_steady.rds")

Check mizerHowTo Customise the match biomass plots to compare the correct ranges

params <- readRDS("phase1_steady.rds")

Check biomass is at steady-state

sim <- project(params, effort = 0)

plotlyBiomass(sim)
plotlyBiomassObservedVsModel(sim)

Check diets

mizer::plotDiet(params)

try to reduce the maximum size of the background resource to force predation among dynamics groups

params_wpp_v1 <- setParams(params, w_pp_cutoff = 100)

params_wpp_v1 <- setResource(params, w_pp_cutoff = 100)
params_wpp_v2 <- steady(params_wpp_v1)
params_wpp_v3 <- tuneParams(params_wpp_v2)
sim_v2 <- project(params_wpp_v1, t_max = 500)
plot(sim_v2)
mizer::plotDiet(params_wpp_v1)
params_guessed_v2 <- params_guessed

params_guessed_v2@species_params$beta[params_guessed_v2@species_params$species == "orca"]  <- 100

Something like ‘yieldCatch’

params_guessed_v2 <- setParams(params_guessed_v2)

sim_v2 <- project(params_guessed_v2, effort=0)

plot(sim_v2)
plotlyFeedingLevel(sim_v2)
plotlyBiomass(sim_v2)
params_v3 <- setParams(params_guessed_v2, w_pp_cutoff = 100000)

sim_v3 <- project(params_v3, effort=0)

plot(sim_v3)
plotlyFeedingLevel(sim_v3)
plotlyBiomass(sim_v3)
theta_v2 <- theta

theta_v2[6,] # small divers
theta_v2[9,] # leopard seals
theta_v2[13,] # orca

theta_v2[6,c(1:4,7,8)] <- 0.5  # small divers
theta_v2[c(1:4,7,8), 6] <- 0.5
theta_v2[9, c(1:4,7,8)] <- 0.5
theta_v2[c(1:4,7,8), 9] <- 0.5
# theta_v2[13, c(1:4,7,8)] 
# theta_v2[13, c(1:4,7,8)]

theta_v2
params_theta_v2 <- newMultispeciesParams(species_params = species_params, 
                                interaction = theta_v2, 
                                w_pp_cutoff = 100000,
                                n = 3/4, p = 3/4)
box.params_v2 <- params_theta_v2

box.params_v2@species_params$ppmr_min[box.params_v2@species_params$species == "baleen whales"]  <- 1e5
box.params_v2@species_params$ppmr_max[box.params_v2@species_params$species == "baleen whales"] <-5e7
box.params_v2@species_params$pred_kernel_type[box.params_v2@species_params$species == "baleen whales"] <- "box"
params_v2 <- box.params_v2

params_v2@species_params$R_max <-params_v2@resource_params$kappa*params_v2@species_params$w_inf^-1.5

params_v2 <- setParams(params_v2)

sim_v2 <- project(params_v2, effort=0)

plot(sim_v2)
plotlyFeedingLevel(sim_v2)
plotlyBiomass(sim_v2)
# plotDiet(sim_v2)
plotSpectra(sim_v2, power = 2)
params_tuned_v1 <- tuneGrowth(params_guessed)
library(mizerMR)
resource_interaction(params_guessed)
#set vectors of plankton and benthos availability for the model species 
plankton_avail <- c(1, 0.8, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5)
# benthos_avail <- c(0.2, 1, 1, 1, 1, 1, 0.5, 0.5, 0.5, 0.5)

#put them into corresponding columns of resource_interaction matrix
resource_interaction(sim_guessed)[, 1] <- plankton_avail
resource_interaction(cur_model)[, 2] <- benthos_avail
# plotBiomassVsSpecies(params_guessed)

# params_v0 <- calibrateBiomass(params_guessed)
# params_v0 <- matchBiomasses(params_guessed)
# resource_params(params_guessed)
# kappa <-  resource_params(params_guessed)$kappa
# lambda <- resource_params(params_guessed)$lambda
# 
# w_max <- 10
# 
# w_full(params_guessed)[[1]]
# w_min <- 1e-12

Setup apex predator resource

# # Set ap_rss kappa same as plankton kappa 
# kappa_ap <- kappa
# 
# # Assume more shallow slope for benthos 
# lambda_ap <- lambda
# # Set maximum ap prey size
# w_max_ap <- 10000000
# # Set minimum ap prey size
# w_min_ap <- 1000
# # Set benthos kappa same as plankton kappa 
# kappa_ben <- kappa
# # Assume more shallow slope for benthos 
# lambda_ben <- 1.9
# # Set maximum benthos size 
# w_max_ben <- 10
# # Benthos starts at larger sizes, corresponding to about 1-2mm
# w_min_ben <- 0.0001

Now we put all these resource parameters into a data frame.

# MFSO_resource_params <- data.frame(
#     resource = c("pl", "ap"),
#     lambda = c(lambda, lambda_ap),
#     kappa = c(kappa,  kappa_ap),
#     w_min = c(w_min, w_min_ap),
#     w_max = c(w_max,  w_max_ap)
# )
# 
# MFSO_resource_params

We can now update our model to use these resource parameters with

# resource_params(params_guessed) <- MFSO_resource_params
# resource_interaction(params_guessed)
# #set vectors of plankton and benthos availability for the model species 
# plankton_avail <- c(1, 1, 1, 1, 1, 1, 1, 1, 1, 0.5, 0.5, 0.25)
# ap_avail <- c(0, 0, 0, 0, 0, 0, 0, 0, 0.25, 0.75, 0.75, 0)
# 
# #put them into corresponding columns of resource_interaction matrix
# resource_interaction(params_guessed)[, 1] <- plankton_avail
# resource_interaction(params_guessed)[, 2] <- ap_avail

Confirm it worked

# resource_interaction(params_guessed)

Try steady for a laugh

MFSO_mod <- steady(params_guessed)

Nah, didn’t think so…hang on a second!

plotlySpectra(MFSO_mod, power = 2)
plotBiomassVsSpecies(MFSO_mod)
MFSO_mod <- calibrateBiomass(MFSO_mod)
plotBiomassVsSpecies(MFSO_mod)
MFSO_mod <- matchBiomasses(MFSO_mod)
plotBiomassVsSpecies(MFSO_mod)
MFSO_mod <- steady(MFSO_mod)
MFSO_mod <- steady(MFSO_mod)
plotBiomassVsSpecies(MFSO_mod)
MFSO_mod <- MFSO_mod |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady()

Increase kappa to help erepro values that are too large. newMultispecies to adjust kappa, or in tuneParams(), but you need to make sure that kappa is actually changing.

plotBiomassVsSpecies(MFSO_mod)
plotSpectra(MFSO_mod, power = 2)
params_v2 <- MFSO_mod

# write_rds(params_v2, "tuned_params.RDS")

params_v2 <- setParams(params_v2)

sim_v2 <- project(params_v2, effort=0)

plot(sim_v2)
plotlySpectra(sim_v2)
# plotDiet(sim_v2)
param_setup <- params_v2
param_setup@resource_params$kappa

param_setup@species_params$R_max[]
param_setup@species_params$erepro[]
params_red_pp_v1 <- param_setup

str(resource_params(params_red_pp_v1))
# mizer::resource_params(params_red_pp_v1)$w_pp_cutoff <- 10

mizer::resource_params(params)[["w_pp_cutoff"]] <- 10
params_red_pp_v1 <- steady(params_red_pp_v1)
MFSO_mod <- matchBiomasses(params_red_pp_v1)
plotBiomassVsSpecies(params_red_pp_v1)
mizerMR::plotlySpectra(param_setup)
mizerMR::plotlySpectra(params_red_pp_v1)
mizerMR::plotDiet(params_red_pp_v1)
params_red_pp_v2 <- setParams(params_red_pp_v1, w_pp_cutoff = 10000)
params_red_pp_v2 <- steady(params_red_pp_v2)
MFSO_mod_v2 <- matchBiomasses(params_red_pp_v2)
plotBiomassVsSpecies(params_red_pp_v2)
mizerMR::plotlySpectra(params_red_pp_v1)
mizerMR::plotlySpectra(params_red_pp_v2)
plotFeedingLevel(params_red_pp_v2, include_critical = T)
mizerMR::plotDiet(params_red_pp_v2)
params_red_pp_v3 <- setParams(params_red_pp_v2, w_pp_cutoff = 1000)
params_red_pp_v3 <- steady(params_red_pp_v3)
MFSO_mod_v3 <- matchBiomasses(params_red_pp_v3)
plotBiomassVsSpecies(params_red_pp_v3)
mizerMR::plotlySpectra(params_red_pp_v2)
mizerMR::plotlySpectra(params_red_pp_v3)
plotFeedingLevel(params_red_pp_v3, include_critical = T)
mizerMR::plotDiet(params_red_pp_v3)
params_red_pp_v4 <- setParams(params_red_pp_v3, w_pp_cutoff = 100)
params_red_pp_v4 <- steady(params_red_pp_v4)
MFSO_mod_v4 <- matchBiomasses(params_red_pp_v4)
plotBiomassVsSpecies(params_red_pp_v4)
mizerMR::plotlySpectra(params_red_pp_v3)
mizerMR::plotlySpectra(params_red_pp_v4)
plotFeedingLevel(params_red_pp_v4, include_critical = T)
mizerMR::plotDiet(params_red_pp_v4)
par_test <- param_setup
# par_test@resource_params$kappa <- 18.3593

# new_vary <- c(param_setup@species_params$R_max, 18.3593)
Rmax_vary <- c(par_test@species_params$R_max)
erepro_vary <- c(par_test@species_params$erepro)
bio_vary <- c(par_test@species_params$R_max, par_test@resource_params$kappa)


getError_Rmax(vary = Rmax_vary, params = par_test, dat = par_test@species_params$biomass_observed, data_type="biomass", timetorun = 100)

getError_erepro(vary = erepro_vary, params = par_test, dat = par_test@species_params$biomass_observed, data_type="biomass", timetorun = 100)

getError_Bio(vary = bio_vary, params = par_test, dat = par_test@species_params$biomass_observed, data_type="biomass", timetorun = 100)
min(param_setup@species_params$R_max[])
max(param_setup@species_params$R_max[])

Optimise

library(parallel)
#create a set of params for the optimisation process
params_optim <- par_test
params_optim <- setParams(params_optim)

#set up workers
noCores <- detectCores() - 2 # keep some spare cores
cl <- makeCluster(noCores, setup_timeout = 0.5)
setDefaultCluster(cl = cl)
clusterExport(cl, as.list(ls()))
clusterEvalQ(cl, {
  library(mizerExperimental)
  library(mizerMR)
  library(optimParallel)
})

optim_result <- optimParallel::optimParallel(par=Rmax_vary,getError_Rmax,params=params_optim, 
                                             dat = params@species_params$biomass_observed, 
                                             data_type="biomass", timetorun = 100, 
                                             method ="L-BFGS-B",
                                             lower=c(rep(1e-20,length(params@species_params$species))),
                                             upper= c(rep(10,length(params@species_params$species))),
                                             parallel=list(loginfo=TRUE, forward=TRUE))
stopCluster(cl)
params_optim@species_params$R_max
# params_optim@species_params$erepro


optim_result$par[1:12]
# optim_result$par[13]
params_optim_v2 <- params_optim
# now put these new Rmaxs
# optim values:
 params_optim_v2@species_params$R_max <- optim_result$par[1:12] # removed the 10^
 # params_optim@species_params$erepro <- optim_result$par[1:12]

 # params_optim@resource_params$kappa <- optim_result$par[13]
 
 # vary_optim <- optim_result$par
 # vary_optim[13] <- 1e3
 # 
 # getErrorBio2(vary = vary_optim,
 #              params_optim, dat = params_optim@species_params$biomass_observed)
 
 #check values ^^ have they gone to max/min etc.
 
params_optim_v2@species_params$max_lim <- 10
params_optim_v2@species_params$min_lim <- 1e-20
# 
params_optim_v2@species_params$R_max > params_optim_v2@species_params$min_lim
params_optim_v2@species_params$R_max < params_optim_v2@species_params$max_lim
 params_optim_v2 <-setParams(params_optim_v2)
 sim_optim <- project(params_optim_v2, effort =0, t_max = 100)

 plot(sim_optim)
 plotlyBiomass(sim_optim)
 plotDiet(sim_optim)

Optimise again

params_optim_v2@resource_params$kappa 
params_optim_v3 <- steady(params_optim_v2)
plotSpectra(params_optim_v3, power =2)
params_optim_v4 <- tuneGrowth(params_optim_v3)
params_optim_v4 <- steady(params_optim_v4)
params_optim_v4 <- readRDS("params_optim_v4.RDS")

sim_v3 <- project(params_optim_v4, effort =0, t_max = 100)
plotBiomassVsSpecies(params_optim_v4)
plotDiet(params_optim_v4)
plotBiomass(sim_v3)
plotlySpectra(sim_v3)
p1 <- plotSpectra(sim_v3)

# saveRDS(params_optim_v4, "params_optim_v4.RDS")
tiff(file="saving_spectra_plot.tiff",
width=6, height=4, units="in", res=500)
p1
dev.off()

If AAD recommend that benthic resource is not meaningful for toothfish

Rmax can be justified by applying a density dependence relationship according to the trait based model (Anderson) If finished with an optim run, could re-introduce density dependence that has been over written by steady()

We don’t know what the level of density dependence should be set at. Can use yield curves, sensitivity to mortality…harvesting

Pristine whale biomass pre-whaling. The ‘base’ model is actually the highly exploited system, can compare historical whaling time series (Chris Clements and Julia have this data)

Body size of whales responding to fishing - Follow

Empricial size distribs of mammals

yield

seaaroundus

We are considering the whales within the Prydz Bay

Gear and catch ability for krill, ice fish and toothfish

Combine Stacey/Roshni model and get a total biomass

params_optim_v4@species_params$erepro
params_optim_v5 <- tuneParams(params_optim_v4)
# params_optim_v5 <- tuneGrowth(params_optim_v4)

getReproductionLevel(params_optim_v4) # no density dependence for groups with 0

# Can try optimise with reproduction level

params_optim_v4@species_params$R_max
params_optim_v4@species_params$erepro

First ecosystem mizer model

# library(parallel)
# #create a set of params for the optimisation process
# # param_optim_v2
# param_optim_v2 <- setParams(param_optim_v2)
# 
# #set up workers
# noCores <- detectCores() - 2 # keep some spare cores
# cl <- makeCluster(noCores, setup_timeout = 0.5)
# setDefaultCluster(cl = cl)
# clusterExport(cl, as.list(ls()))
# clusterEvalQ(cl, {
#   library(mizerExperimental)
#   library(mizerMR)
#   library(optimParallel)
# })
# 
# optim_result <- optimParallel::optimParallel(par=bio_vary,getError_Bio,params=params_optim, 
#                                              dat = params@species_params$biomass_observed, 
#                                              data_type="biomass", timetorun = 100, 
#                                              method ="L-BFGS-B",
#                                              lower=c(rep(1e-20,length(params@species_params$species)),1),
#                                              upper= c(rep(10,length(params@species_params$species)),1e+15),
#                                              parallel=list(loginfo=TRUE, forward=TRUE))
# stopCluster(cl)

Add Benthic Resource Spectrum

# Set benthos kappa same as plankton kappa
kappa_ben <- kappa
# Assume more shallow slope for benthos
lambda_ben <- 1.9
# Set maximum benthos size
w_max_ben <- 10
# Benthos starts at larger sizes, corresponding to about 1-2mm
w_min_ben <- 0.0001

Now we put all these resource parameters into a data frame.

MFSO_resource_params_v2 <- data.frame(
    resource = c("pl", "ap", "bb"),
    lambda = c(lambda, lambda_ap, lambda_ben),
    kappa = c(kappa,  kappa_ap, kappa_ben),
    w_min = c(w_min, w_min_ap, w_min_ben),
    w_max = c(w_max,  w_max_ap, w_max_ben)
)

MFSO_resource_params_v2
params_bb <- params_optim_v4
#set vectors of plankton and benthos availability for the model species 
plankton_avail <- c(1, 1, 1, 1, 1, 1, 1, 1, 1, 0.5, 0.5, 0.25)
ap_avail <- c(0, 0, 0, 0, 0, 0, 0, 0, 0.25, 0.75, 0.75, 0)
bb_avail <- c(0.1, 0, 0.25, 0.25, 0, 0.25, 0.25, 0.5, 0.25, 0, 0, 0)


#put them into corresponding columns of resource_interaction matrix
resource_interaction(params_bb)[, 1] <- plankton_avail
resource_interaction(params_bb)[, 2] <- ap_avail
resource_interaction(params_bb)[, 3] <- bb_avail

We can now update our model to use these resource parameters with


params_optim_v5 <- setMultipleResources(params_optim_v4, MFSO_resource_params_v2)

resource_params(params_optim_v4) <- MFSO_resource_params_v2
resource_interaction(params_optim_v4)
#set vectors of plankton and benthos availability for the model species 
plankton_avail <- c(1, 1, 1, 1, 1, 1, 1, 1, 1, 0.5, 0.5, 0.25)
ap_avail <- c(0, 0, 0, 0, 0, 0, 0, 0, 0.25, 0.75, 0.75, 0)

#put them into corresponding columns of resource_interaction matrix
resource_interaction(params_guessed)[, 1] <- plankton_avail
resource_interaction(params_guessed)[, 2] <- ap_avail

Confirm it worked

resource_interaction(params_guessed)
LS0tDQp0aXRsZTogIk1GU08gVGlua2VyaW5nIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NClRoaXMgdmVyc2lvbiBpbmNsdWRlcyBwYXJhbXNfdjIsIHdoaWNoIGhhcyB0aGUgZXhwYW5kZWQgbnVtYmVyIG9mIHpvb3BsYW5rdG9uIGdyb3Vwcw0KDQpQaGFzZSAxDQpLYXBwYSBzdGFydGluZyBwb2ludDogdXNlIHZhbHVlIG9mIDEwIHQva21eMiBmcm9tIE1jQ29ybWFjayBldCBhbC4gMjAyMCB0byBlc3RhYmxpc2ggYSBzdGVhZHkgbW9kZWwuDQpNYXRjaCBtb2RlbCB0byB0aW1lLWF2ZXJhZ2VkIGZpc2hpbmcgKGNhdGNoKQ0KDQpQaGFzZSAyDQpUaGVuIHVzZSBoaXN0b3JpY2FsIEZpc2hNSVAgdmFsdWVzIHRvIGVzdGltYXRlIHRoZSBwcm9maWxlIG9mIHRoZSBwaHl0b3BsYWt0b24gc2l6ZSBzcGVjdHJ1bQ0KDQpBQ0VBUyBkYXRhOg0KQ2FuIHdlIGdldCBlbXBpcmljYWwgcGh5dG9wbGFua3RvbiBvciB6b29wbGFua3RvbiBzaXplIHNwZWN0cmEgKEJDRyBBUkdPIGZsb2F0cyBvciBwYXJ0aWNsZSBjb3VudGVycykgSmFzZSBFdmVyZXR0IG9yIEFDRUFTIGZvbGtzDQoNClVzaW5nIHBpY28gKDYuOTQ1NTllLTExKSBhbmQgbGFyZ2UgKDYuMDYxMzFlLTA3KSAgcGh5dG8gbWlkcG9pbnRzIGZyb20gUGhvZWJlJ3MgbWV0aG9kIGFzIHRoZSBhc3N1bWVkIHBoeXRvcGxhbmt0b24gc2l6ZSByYW5nZS4gJ1NwcmVhZCcgdGhlIGJpb21hc3MgZXN0aW1hdGUgZnJvbSBNY0Nvcm1hY2sgb2YgMTAgdC9rbV4yIGFjcm9zcyB0aGF0IHNpemUgcmFuZ2UgYW5kIHVzaW5nIEJhcm5lcyBlcXVhdGlvbiB0byBlc3RpbWF0ZSB0aGUgZGVuc2l0eSBhdCB0aGUgaW50ZXJjZXB0IChkZW5zaXR5IHBlciBncmFtIGF0IDAgb24gbG9nIHNjYWxlKToga2FwcGEgPSAxNy45IA0KDQpLYXBwYSBmb3IgdGhlIHdob2xlIG1vZGVsIGRvbWFpbiBpcyAxNy45ICogMS40NzQzNDFlKzEyID0gMi42MzkwN2UrMTMNCg0KU2V0dGluZyBrYXBwYToNCkhvdyBkbyB3ZSB3YW50IHRvIGV4cHJlc3MgdGhlIG1vZGVsIGRvbWFpbi4gbV4yIG9yIHRoZSBlbnRpcmUgZG9tYWluIHZvbHVtZT8NCkJhbnphcmUgQmFuayBtb2RlbCBkb21haW4gaXMgMS40NzQzNDFlKzEyIFttXjJdDQoNCkRldGVybWluZSB0aGUgc2l6ZSByYW5nZSBmb3IgdGhlIHBoeXRvcGxhbmt0b24gZnJvbSBTdGFjZXkncyBtb2RlbA0KLSBNYWtlIHN1cmUgaXQncyBkZW5zaXR5IHBlciANCg0KQ2FuIHVzZSBoaXN0b3JpY2FsIGZpc2hNSVAgdmFsdWVzIHRvIGVzdGltYXRlIHRoZSBrYXBwYSB2YWx1ZQ0KDQpodHRwczovL2dpdGh1Yi5jb20vcHdvb2R3b3J0aC1qZWZjb2F0cy90aGVyTWl6ZXItRmlzaE1JUC0yMDIyLUhJL2Jsb2IvbWFpbi9DbGltYXRlRm9yY2luZy9QbGFua3Rvbi9QcmVwX1BsYW5rdG9uX3RoZXJNaXplci5SbWQNCiogRG91YmxlIGNoZWNrIGFsbCB1bml0cyB0byBtYWtlIHN1cmUgdGhleSBtYXRjaA0KKiBTaXplIGNsYXNzZXMgaGFyZC1jb2RlZCBzbyBtYWtlIHN1cmUgdG8gZWRpdCANCiogdGltZSBzdGVwcyBhbHNvIGhhcmQtY29kZWQgKG5lZWQgdG8gYWRqdXN0IHRoZSBhcnJheXMpDQoNClRvIGdldCB0aGUgc3RhcnRpbmcgcG9pbnQgZm9yIFBob2ViZSdzIHNjcmlwdCwgbmVlZCBhIHRpbWVzZXJpZXMgb2YgdG90YWwgY2FyYm9uIGRlbnNpdHkNCg0KU3RlYWR5IHN0YXRlIGlzIHRoZSBiYXNlIG1vZGVsIChudWxsIGh5cG90aGVzaXMuLikgdGhhdCBmdWxmaWxscyB0aGUgZm9sbG93aW5nIGNyaXRlcmlhLg0KSXQgYWxsb3dzIHVzIHRvIGludmVzdGlnYXRlIGNoYW5nZSByZWxhdGl2ZSB0byB0aGUgYmFzZSBtb2RlbC4NCg0KQ2xlYXIgcnVsZSBmb3IgdGhlIG1vZGVsIHRvIHJlcHJlc2VudCBlbmRvdGhlcm1zDQoNCldpdGhpbiAyNSUgYmlvbWFzcyBlc3RpbWF0ZXMNCg0KUmVhbGlzZWQgUFBNUnMgYXJlIGNvbnNpc3RlbnQgd2l0aCBlbXBpcmljYWwga25vd2xlZGdlDQoNCk9udG9nZW5ldGljIHNoaWZ0cw0KDQpVbmV4cGxvaXRlZCBzaXplIHNwZWN0cnVtIHRoYXQgaXMgd2l0aGluICd4JyBvZiB0aGUgZXhwZWN0ZWQgYnkgdGhlb3J5IChkZWZpbml0ZWx5IG5lZ2F0aXZlKQ0KDQpTaGVsZG9uIGJpb21hc3MgZGlzdHJpYnV0aW9uID0gYXBwcm94LiAwDQoNCkVtZXJnZW50IHZlcnN1cyBjb25zdHJhaW5lZA0KDQpQcm9kdWN0aW9uIHRvIGJpb21hc3MgcmF0aW9zIC0gRWNvcGF0aCBlc3RpbWF0ZXMNCg0KdHJvcGhpYyBsZXZlbCBjb21wYXJpc29uIHdpdGggZWNvcGF0aCBtb2RlbHMNCg0KQm9ycm93aW5nIGZyb20gb3RoZXIgbW9kZWxzLCBwaWVjaW5nIHRoZSBldmlkZW5jZSB0b2dldGhlciB0byBhbGxvdyB1cyB0byBleHBsb3JlIHRoZSBTJkYgb2YgZWNvc3lzdGVtIHdpdGggcGxhbmt0b24gdG8gd2hhbGVzLg0KDQpLRVkgUVVFU1RJT05TOg0KDQpXaGF0IGFyZSB0aGUgZW1lcmdlbnQgZWNvc3lzdGVtIHByb3BlcnRpZXMsIHByb2R1Y3Rpdml0eSwgcmVzaWxpZW5jZSBldGMsIA0KDQpIb3cgc2Vuc2l0aXZlIGFyZSBlY29zeXN0ZW0gcHJvcGVydGllcyB0byBwZXJ0dXJiYXRpb24gb2YgdW5jZXJ0YWluIHBhcmFtZXRlcnMgKG1lc29wZWxhZ2ljIGJpb21hc3MsIGthcHBhIGV0YykNCg0KDQpMb2FkIGxpYnJhcmllcyANCmBgYHtyfQ0KcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInNpemVzcGVjdHJ1bS90aGVyTWl6ZXIiKSAjIGlmIG5lZWRlZA0KbGlicmFyeSh0aGVyTWl6ZXIpDQojIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJzaXplc3BlY3RydW0vbWl6ZXJFeHBlcmltZW50YWwiKQ0KIyBsaWJyYXJ5KG1pemVyRXhwZXJpbWVudGFsKQ0KIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigic2l6ZXNwZWN0cnVtL21pemVyTVIiKQ0KIyBsaWJyYXJ5KG1pemVyKQ0KIyBsaWJyYXJ5KG1pemVyTVIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCiMgbGlicmFyeShwbG90bHkpDQojIGxpYnJhcnkobGhzKQ0KYGBgDQoNCkxvYWQgZ3JvdXAgcGFyYW1ldGVycw0KDQpgaGAgdmFsdWVzIGZyb20gZGF0YSBmb3Igc29tZSBncm91cHMuDQpDYW4gdHJ5IGRldmVsb3BpbmcgYSBtb2RlbCB3aXRoIHRoZW0gaW50aXRhbGx5LCBidXQgaXQgbWF5IHJlcXVpcmUgZGVsZXRpbmcgYWxsIGBoYCB2YWx1ZXMgYW5kIHByb2NlZWRpbmcgZnJvbSB0aGUgYmVnaW5uaW5nIGFnYWluIHdpdGggZGVmYXVsdCBjYWx1Y2xhdGlvbnMgZnJvbSBtaXplciB1c2luZyBga192YmANCg0Ka192Yl9zdHJpbmcgPC0gYygwLjQsMC4zNjA4MzMzLDAuMTgyNSwwLjE1LDEsMC4yLDAuNSwwLjA2LDAuMiwwLjIsMC4yLDAuMiwwLjIsMC4yLDAuMikgIyB0byB1c2UgYWxsIGtfdmIgdmFsdWVzIGFuZCBpbnN0ZWFkIG9mIGgNCg0KYGBge3J9DQojIGdyb3Vwc19yYXcgPC0gcmVhZC5jc3YoImdyb3VwIHBhcmFtcy90cmFpdF9ncm91cHNfcGFyYW1zX3ZDV0MuY3N2IikNCiMgZ3JvdXBzX3JhdyA8LSByZWFkLmNzdigiZ3JvdXAgcGFyYW1zL3RyYWl0X2dyb3Vwc19wYXJhbXNfdkNXQ192Mi5jc3YiKQ0KZ3JvdXBzX3JhdyA8LSByZWFkLmNzdigiZ3JvdXAgcGFyYW1zL3RyYWl0X2dyb3Vwc19wYXJhbXNfdkNXQ192Mi5jc3YiKVssLTFdDQpncm91cHNfcmF3DQpgYGANCg0KRmlsbCBpbiBtaXNzaW5nIGFuZCBhZGp1c3QgYmV0YSB2YWx1ZXMgZm9yIHpvb3BsYW5rdG9uIGdyb3VwcyB1c2luZyBIZW5lZ2hhbiBldCBhbC4gMjAyMCAoMTAuMTAxNi9qLmVjb2xtb2RlbC4yMDIwLjEwOTI2NSkNCg0KTmVlZCBhIHZhbHVlIGZvciBtaWNyb3pvb3BsYW5rdG9uDQptaWNyb3pvb3BsYW5rdG9uIChpbiBNY0Nvcm1hY2sgZXQgYWwuIDIwMjApIGlzIGNvbXBvc2VkIG9mIEhldGVyb3Ryb3BoaWMgZGlub2ZsYWdlbGxhdGVzLCB0aW50aW5uaWRzLCBjaWxpYXRlcywgY29wZXBvZCBuYXVwbGlpDQpIZW5lZ2hhbiBldCBhbC4gbG9nMTBQUE1SIHZhbHVlcyBmb3I6DQpIZXRlcm8uRmxhZ2VsbGF0ZXMgPSAwLjLigJMwLjcyIC0+IDAuNDYNCkhldGVyby5DaWxpYXRlcyA9IDIuNeKAkzIuOSAtPiAyLjcNCk1lYW46ICgyLjcrMC40NikvMiA9IDEuNTgNCjEwXjEuNTggPSAzOC4wMTg5NA0KDQpOZWVkIHRvIGFkanVzdCB2YWx1ZXMgZm9yIG1lc296b28sIG90aGVyIG1hY3Jvem9vLCBldXBoYXVzaWlkcywgc2FscHMNCg0KSGVuZWdoYW4gZXQgYWwuIGxvZzEwUFBNUiB2YWx1ZXMgKG1pZHBvaW50cyBmb3IgcmFuZ2UpIGZvcjoNCnNhbHBzID0gNi444oCTMTEuNyAtPiA5LjI1DQoxMF45LjI1ID0gMTc3ODI3OTQxMA0KDQpldXBoYXVzaWlkcyA9IDYuNuKAkzcuOCAtPiA3LjINCjEwXjcuMiA9IDE1ODQ4OTMyDQoNCm1lc296b28gKGNvcGVwb2RzKQ0KT21uaS5Db3AuID0gMy424oCTNC42IC0+IDQuMQ0KQ2Fybi5Db3AuID0gMC444oCTMS45IC0+IDEuMzUNCk1lYW46ICg0LjErMS4zNSkvMiA9IDIuNzI1DQoxMF4yLjcyNSA9IDUzMC44ODQ0DQoNCm90aGVyIG1hY3Jvem9vICgpDQpDaGFldG9nbmF0aHMgPSAxLjnigJMzLjQgLT4gMi42NQ0KMTBeMi42NSA9IDQ0Ni42ODM2DQoNCmBgYHtyfQ0KZ3JvdXBzX3JhdyRiZXRhWzFdICMgbWljcm96b29wbGFudGtvbg0KZ3JvdXBzX3JhdyRiZXRhWzJdICMgbWVzb3pvb3BsYW50a29uLCBleGlzaXRuZyB2YWx1ZSBvZiA1MDAgaXMgc3VpdGFibGUNCmdyb3Vwc19yYXckYmV0YVszXSAjIG90aGVyIG1hY3Jvem9vcGxhbnRrb24sIGV4aXNpdG5nIHZhbHVlIG9mIDUwMCBpcyBzdWl0YWJsZQ0KZ3JvdXBzX3JhdyRiZXRhWzRdICMgZXVwaGF1c2lpZHMgDQpncm91cHNfcmF3JGJldGFbNV0gIyBzYWxwcw0KDQpncm91cHNfcmF3JGJldGFbMV0gPC0gMzguMDE4OTQgIyBtaWNyb3pvb3BsYW50a29uICNncm91cHNfcmF3JGJldGFbMV0gPC0gMzguMDE4OTQgIyBtaWNyb3pvb3BsYW50a29uDQojIGdyb3Vwc19yYXckYmV0YVsyXSAjIG1lc296b29wbGFudGtvbiANCiMgZ3JvdXBzX3JhdyRiZXRhWzNdICMgb3RoZXIgbWFjcm96b29wbGFudGtvbg0KZ3JvdXBzX3JhdyRiZXRhWzRdIDwtIDE1ODQ4OTMyICMgZXVwaGF1c2lpZHMNCmdyb3Vwc19yYXckYmV0YVs1XSA8LSAgMTc3ODI3OTQxMCAjIHNhbHBzDQoNCmdyb3Vwc19yYXckYmV0YVsxXSAjIG1pY3Jvem9vcGxhbnRrb24NCmdyb3Vwc19yYXckYmV0YVsyXSAjIG1lc296b29wbGFudGtvbiwgZXhpc2l0bmcgdmFsdWUgb2YgNTAwIGlzIHN1aXRhYmxlDQpncm91cHNfcmF3JGJldGFbM10gIyBvdGhlciBtYWNyb3pvb3BsYW50a29uLCBleGlzaXRuZyB2YWx1ZSBvZiA1MDAgaXMgc3VpdGFibGUNCmdyb3Vwc19yYXckYmV0YVs0XSAjIGV1cGhhdXNpaWRzIA0KZ3JvdXBzX3JhdyRiZXRhWzVdICMgc2FscHMNCmBgYA0KDQoNCmBgYHtyfQ0KIyBncm91cHNfcmF3Wyw4XSAjIGNvbmZpcm0gd2hhdCBjb2x1bW4gYGhgIGlzDQoNCmdyb3Vwc19yYXckaA0KDQpoX3VwZGF0ZSA8LSBjKDMzLjAsICAzMy4wLCAgMzMuMCwgIDMzLjAsICAzMy4wLCAgICBOQSwgICAgTkEsICAgIE5BLCAxODkuMCwgIDY2LjAsICAgIE5BLCAgICBOQSwgIE5BLCAgTkEsICBOQSwgIE5BLCAgTkEsICAgTkEsICAgTkEpDQoNCmdyb3Vwc19yYXckaCA8LSBoX3VwZGF0ZQ0KDQojIGdyb3Vwc19ub19oIDwtIGdyb3Vwc19yYXdbLC04XQ0KDQojIGdyb3Vwc19ub19oJGJpb21hc3Nfb2JzZXJ2ZWQNCg0KIyBncm91cHMgPC0gZ3JvdXBzX25vX2gNCg0Ka192Yl9zdHJpbmcgPC0gYygwLjYsMC40LDAuNCwwLjQsMC40LDAuMzYwODMzMywwLjE4MjUsMC4xNSwxLDAuMiwwLjUsMC4wNiwwLjIsMC4yLDAuMiwwLjIsMC4yLDAuMiwwLjIpICMgdG8gdXNlIGFsbCBrX3ZiIHZhbHVlcyBhbmQgaW5zdGVhZCBvZiBoDQoNCmdyb3Vwc19yYXcka192YiA8LSBrX3ZiX3N0cmluZw0KIyBncm91cHMka192YiA8LSBrX3ZiX3N0cmluZw0KDQojIHNwZWNpZXNfcGFyYW1zIDwtIGdyb3Vwcw0KDQojIHNwZWNpZXNfcGFyYW1zWzYsNF0gI21heCBzaXplIGZvciBzbWFsbCBkaXZlcnMNCiMgc3BlY2llc19wYXJhbXNbNiwzXSAjbWF0dXJhdGlvbiBzaXplDQojIHNwZWNpZXNfcGFyYW1zWzYsMl0gI21pbmltdW0gc2l6ZQ0KIyANCiMgc3BlY2llc19wYXJhbXNbNiwzXSA8LSAwLjg1KnNwZWNpZXNfcGFyYW1zWzYsNF0NCiMgc3BlY2llc19wYXJhbXNbOSwzXSA8LSAwLjk5KnNwZWNpZXNfcGFyYW1zWzksNF0NCiMgDQojIGdyb3Vwc19yYXdbNiwzXSA8LSAwLjg1Kmdyb3Vwc19yYXdbNiw0XQ0KIyBncm91cHNfcmF3WzksM10gPC0gMC45OSpncm91cHNfcmF3WzksNF0NCmxlbmd0aChncm91cHNfcmF3JHNwZWNpZXMpDQpsZW5ndGgoZ3JvdXBzX3JhdyRoKQ0KbGVuZ3RoKGdyb3Vwc19yYXcka192YikNCg0KZ3JvdXBzX3JhdyRoDQpncm91cHNfcmF3JGtfdmINCmdyb3VwcyA8LSBncm91cHNfcmF3DQpgYGANCg0KDQpVcGRhdGUgbWF4IGFuZCBtYXQgc2l6ZSBmb3Igb3JjYSB1c2luZyBzZWFsaWZlYmFzZSB2YWx1ZXMgcmF0aGVyIHRoYW4gdGhlIHByZXZpb3VzIHdfbWF4IG9mIDZ0DQpgYGB7cn0NCmdyb3VwcyRzcGVjaWVzWzE3XQ0KZ3JvdXBzJHdfbWF4WzE3XQ0KZ3JvdXBzJHdfbWF0WzE3XQ0KDQpncm91cHMkd19tYXhbMTddIDwtIDEwNjI4MDM0DQoNCmdyb3VwcyR3X21hdFsxN10gPC0gMzE5ODg1NQ0KDQpncm91cHMkd19tYXhbMTddDQpncm91cHMkd19tYXRbMTddDQpncm91cHMkd19tYXQyNVsxN10NCmBgYA0KDQoNClVwZGF0ZSBtYXggYW5kIG1hdCBzaXplIGZvciBsZW9wYXJkIHNlYWwgdXNpbmcgc2VhbGlmZWJhc2UgdmFsdWVzLiBNYXggd2VpZ2h0IG9ic2VydmVkIHJlcG9ydGVkIGFzIDQ1MGtnLiBVc2luZyB0aGUgc2VhbGlmZWJhc2UgdmFsdWVzIGZvciBMLVcgY29udmVyc2lvbiBhbmQgbWF4IGxlbmd0aCByZXN1bHRzIGluIGFuIGVzdGltYXRlZCBtYXggd2VpZ2h0IG9mIDU0NTg3NS4yZywgd2hpY2ggaXMgdG9vIGhpZ2ggYWJvdmUgdGhlIG1heCB3ZWlnaHQgb2JzZXJ2ZWQuDQpgYGB7cn0NCmdyb3VwcyRzcGVjaWVzWzEzXQ0KZ3JvdXBzJHdfbWF4WzEzXQ0KZ3JvdXBzJHdfbWF0WzEzXQ0KDQpncm91cHMkd19tYXhbMTNdIDwtIDQ1MDAwMA0KIA0KZ3JvdXBzJHdfbWF4WzEzXQ0KZ3JvdXBzJHdfbWF0WzEzXQ0KZ3JvdXBzJHdfbWF0MjVbMTNdDQpgYGANCg0KYGBge3J9DQpncm91cHNbLDddICMgY29uZmlybSB3aGF0IGNvbHVtbiBgaGAgaXMNCg0KIyBncm91cHNfbm9faCA8LSBncm91cHNbLC03XQ0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KZGZfaW5kX0NQVUUgPC0gcmVhZFJEUygiaW5kX2NhdGNoX3dlaWdodF9CYW56YXJlQmFua18xOTMwXzIwMTlfQ1BVRS5yZHMiKQ0KZGZfQ1BVRV9rZ19kYXkgPC0gcmVhZFJEUygiY2F0Y2hfdGltZXNlcmllc19CYW56YXJlQmFua18xOTMwXzIwMTlfQ1BVRS5yZHMiKQ0KDQpnbGltcHNlKGRmX2luZF9DUFVFKQ0KZ2xpbXBzZShkZl9DUFVFX2tnX2RheSkNCmBgYA0KDQpZaWVsZCBmb3IgdGhlIHBlcmlvZCB0aGF0IG1hdGNoZXMgRWNvcGF0aCBtb2RlbCwgcG9zdCAyMDAwIGFubnVhbCBhdmVyYWdlDQpgYGB7cn0NCmRmX3lpZWxkXzIwMDBfMjAxOSA8LSBkZl9DUFVFX2tnX2RheSAlPiUgDQogIGZpbHRlcihZZWFyID4gMjAwMCkgJT4lIA0KICBncm91cF9ieShTcGVjaWVzKSAlPiUgDQogIHN1bW1hcmlzZSh5aWVsZCA9IHN1bSh0b3RhbF9jYXRjaF9rZykvMTkpDQoNCmRmX3lpZWxkXzIwMDBfMjAxOQ0KYGBgDQoNCkFkZCB5aWVsZCBpbiB0b25uZXMgcGVyIGttMiwgc2FtZSBhcyBnIG0yIGFuZCBpdCBpcyBjb25zaXN0ZW50IHdpdGggYGJpb21hc3Nfb2JzZXJ2ZWRgIA0KDQoxLjQ3NDM0MWUrMTIgbV4yIGZvciBtb2RlbCBkb21haW4NCg0KMS40NzQzNDFlKzEyLzFlKzYgPSAxNDc0MzQxIGttXjINCg0KNTA3NTExIGtnIG9mIG1pbmtlIHdoYWxlIHBlciB5ZWFyIGZyb20gMjAwMCAtIDIwMTkNCg0KNTA3LjUvMTQ3NDM0MSA9IDAuMDAwMzQ0MjIxNiB0b25uZXMgTWlua2Ugd2hhbGUgeWllbGQgcGVyIGttMiBmcm9tIDIwMDAgLSAyMDE5DQoNCjE1NjE5LjI0IGtnIG9mIGJhbGVlbiB3aGFsZSBwZXIgeWVhciBmcm9tIDIwMDAgLSAyMDE5DQoNCjE1LjYvMTQ3NDM0MSA9IDEuMDU4MWUtMDUgdG9ubmVzIG9mIGJhbGVlbiB3aGFsZSBwZXIga20yIGZyb20gMjAwMCAtIDIwMTkNCg0KYGBge3J9DQp5aWVsZF9vYnNlcnZlZCA8LSBjKDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAuMDAwMzQ0MjIxNiwgMCwgMCwgMS4wNTgxZS0wNSkgIyB0byBhZGQgYSB5aWVsZF9vYnNlcnZlZCBjb2x1bW4gaW4gc3BlY2llc19wYXJhbXMNCg0KZ3JvdXBzJHlpZWxkX29ic2VydmVkIDwtIHlpZWxkX29ic2VydmVkDQpgYGANCg0KYGBge3J9DQpiaW9tYXNzX2N1dG9mZiA8LSBjKDAsIDAsIDAsIDAuMSwgMC4xLCAxLCAxLCAxLCA0MCwgNDUwMCwgMSwgMSwgMjAwMDAwLCAxMDAwMCwgMTM1MDAwLCA2MDAwMDAsIDQ5MDAwMCwgMzY1MDAwMCwgMjI1MDAwMCkgIyB0byBhZGQgYSBiaW9tYXNzX2N1dG9mZiBjb2x1bW4gaW4gc3BlY2llc19wYXJhbXMNCg0KZ3JvdXBzJGJpb21hc3NfY3V0b2ZmIDwtIGJpb21hc3NfY3V0b2ZmDQpgYGANCg0KDQpgYGB7cn0NCmdyb3VwcyB8PiBkcGx5cjo6c2VsZWN0KHNwZWNpZXMsIHlpZWxkX29ic2VydmVkLCBiaW9tYXNzX29ic2VydmVkLCBiaW9tYXNzX2N1dG9mZiwgd19taW4pDQpgYGANCg0KDQpgYGB7cn0NCmdyb3Vwc19maW5hbCA8LSBncm91cHNbLWMoMTozKSxdDQoNCmdyb3Vwc19maW5hbA0KYGBgDQoNCg0KDQoNClJ1biBhIHJhbmdlIG9mIG1vZGVscyB0byBkaWZmZXJlbnQgYmlvbWFzcyBlc3RpbWF0ZXMgDQpVc2UgYW4gZW5zZW1ibGUgYXBwcm9hY2gNClBlcnR1cmJhdGlvbiB0byB0ZXN0IHRoZSBjaGFuZ2UgaW4gc2l6ZSBzdHJ1Y3R1cmUgYW5kIGZ1bmN0aW9ucw0KDQpMb2FkIGludGVyYWN0aW9uIG1hdHJpeA0KYGBge3J9DQp0aGV0YSA8LSByZWFkUkRTKCJ0cmFpdF9ncm91cHNfaW50ZXJhY3Rpb25fbWF0cml4X3ZDV0NfdjIuUkRTIikNCnRoZXRhDQpgYGANCg0KSW50ZXJhY3Rpb24gYmV0d2VlbiBvcmNhIHNob3VsZCBiZSAwLCBzbyB0aGlzIG5lZWRzIHRvIGJlIGFkanVzdGVkIGZyb20gb3JpZ2luYWwNCg0KYGBge3J9DQojIHRoZXRhWzEzLDEzXQ0KdGhldGFbMTcsMTddDQoNCnRoZXRhWzE3LDE3XSA8LSAwDQoNCnRoZXRhWzE3LDE3XQ0KYGBgDQoNCmBgYHtyfQ0KdGhldGFfZmluYWwgPC0gdGhldGFbLSgxOjMpLC0oMTozKV0NCg0KdGhldGFfZmluYWwNCmBgYA0KDQpBZGRpbmcgbWluIGFuZCBtYXggdGVtcCBmb3IgZWFjaCBncm91cA0KDQpVc2luZyBzZWFsaWZlYmFzZSBmb3IgYWxsIG5vbi1maXNoIHNwZWNpZXMvZ3JvdXBzLiBJbiBtb3N0IGNhc2VzLCB0aGVyZSBhcmUgbm8gbGlzdGVkIFRlbXBlcmF0dXJlIHZhbHVlcyBpbiB0aGUgJ0Vudmlyb25tZW50JyBzZWN0aW9uLCBsaWtlIHRoZXJlIGlzIGZvciBtb3JlIGRhdGEtcmljaCBzcGVjaWVzLCBlLmcuLCBjb2QNCg0KSW5zdGVhZCwgdGhlcmUgYXJlIHZhbHVlcyBhdCB0aGUgYm90dG9tIG9mIHRoZSBzZWFsaWZlYmFzZSBwYWdlcyBpbiAnRXN0aW1hdGVzIG9mIHNvbWUgcHJvcGVydGllcyBiYXNlZCBvbiBtb2RlbHMnIHdpdGggJ1ByZWZlcnJlZCB0ZW1wZXJhdHVyZScgZXN0aW1hdGVzIGZyb20gdGhlIEFxdWFNYXBzIG1vZGVsLWJhc2VkIGFwcHJvYWNoIChodHRwczovL3d3dy5nYmlmLm9yZy90b29sLzgxMzU2L2FxdWFtYXBzLXByZWRpY3RlZC1yYW5nZS1tYXBzLWZvci1hcXVhdGljLXNwZWNpZXMpICANCg0KWzFdICJldXBoYXVzaWlkcyI6DQpBbnRhcmN0aWMga3JpbGwgLSAoUHJlZmVycmVkIHRlbXBlcmF0dXJlIChSZWYuIDExNTk2OSk6IC0xLjUgLSAxLjYsIG1lYW4gMC4yIChiYXNlZCBvbiA1MzUgY2VsbHMpKQ0KQ3J5c3RhbCBrcmlsbCAtIChQcmVmZXJyZWQgdGVtcGVyYXR1cmUgKFJlZi4gMTE1OTY5KTogLTEuOCAtIDEuMSwgbWVhbiAtMS42IChiYXNlZCBvbiAzNTg4IGNlbGxzKSkgDQpUaHlzYW5vZXNzYSBtYWNydXJhIC0gKFByZWZlcnJlZCB0ZW1wZXJhdHVyZSAoUmVmLiAxMTU5NjkpOiAtMS4yIC0gMi44LCBtZWFuIDAuMiAoYmFzZWQgb24gMjQgY2VsbHMpLiBOb3QgaW5jbHVkZWQgZHVlIHRvIHNtYWxsIG51bWJlciBvZiBjZWxscyBhbmQgbG93IGNvbnRyaWJ1dGlvbiB0byBiaW9tYXNzIGluIHRoaXMgbW9kZWwgZG9tYWluDQpbMl0ibWVzb3BlbGFnaWMgZmlzaGVzIiAtIEVsZWN0cm9uYSBhbnRhcmN0aWNhKG5vdGhpbmcgb24gZmlzaGJhc2UpICAgIA0KWzNdImJhdGh5cGVsYWdpYyBmaXNoZXMiICAgICAgDQpbNF0ic2hlbGYgYW5kIGNvYXN0YWwgZmlzaGVzIjoNCk1hcmJsZWQgcm9ja2NvZCAoLTEgLSA1KQ0KWzVdImZseWluZyBiaXJkcyI6DQpTb3V0aGVybiBnaWFudCBwZXRyZWwgKFByZWZlcnJlZCB0ZW1wZXJhdHVyZSAoUmVmLiAxMTU5NjkpOiAyLjEgLSAxNS42LCBtZWFuIDEwLjEgKGJhc2VkIG9uIDUzMyBjZWxscykpOw0KQXJjdGljIHRlcm4gKFN0ZXJuYSBwYXJhZGlzYWVhKSAoUHJlZmVycmVkIHRlbXBlcmF0dXJlIChSZWYuIDExNTk2OSk6IDAuNCAtIDEzLjMsIG1lYW4gNi44IChiYXNlZCBvbiAyNDY4IGNlbGxzKSkNClRoYWxhc3NhcmNoZSBjaHJ5c29zdG9tYSAoR3JleS1oZWFkZWQgcGV0cmVsKSAgKFByZWZlcnJlZCB0ZW1wZXJhdHVyZSAoUmVmLiAxMTU5NjkpOiAxLjMgLSA5LjEsIG1lYW4gNS4yIChiYXNlZCBvbiAyNjMgY2VsbHMpKQ0KU291dGggcG9sYXIgc2t1YSAoUHJlZmVycmVkIHRlbXBlcmF0dXJlIChSZWYuIDExNTk2OSk6IDAuMiAtIDE4LjIsIG1lYW4gNi40IChiYXNlZCBvbiAxMzE4IGNlbGxzKSkNCkRpb21lZGVhIGV4dWxhbnMgKFdhbmRlcmluZyBhbGJhdHJvc3MpLCAoUHJlZmVycmVkIHRlbXBlcmF0dXJlIChSZWYuIDExNTk2OSk6IDAuNSAtIDEyLCBtZWFuIDQuNiAoYmFzZWQgb24gMTUyOCBjZWxscylfDQpbNl0ic21hbGwgZGl2ZXJzIiAtIG5vIGluZm8gZm9yIGFkZWxpZSwgZ2VudG9vIG9yIGNyZXN0ZWQgcGVuZ3VpbnMgb24gc2VhbGlmZWJhc2UuIEd1ZXNzIGJhc2VkIG9uIG1lZGl1bSBkaXZlcnMgICAgICAgDQpbN10ic3F1aWRzIiAtIGJhc2VkIG9uIFBzeWNocm90ZXV0aGlzIGdsYWNpYWxpcyAoc2VhbGlmZWJhc2UpICAgICAgICAgICAgICAgICAgIA0KWzhdInRvb3RoZmlzaGVzIiAtIG5vIGRhdGEgb24gZmlzaGJhc2UgICAgICAgICAgICANCls5XSJsZW9wYXJkIHNlYWxzIiAtIFByZWZlcnJlZCB0ZW1wZXJhdHVyZSAoUmVmLiAxMTU5NjkpOiAtMS45IC0gMS40LCBtZWFuIC0wLjUgKGJhc2VkIG9uIDIxMDkgY2VsbHMpLiAgICAgICAgICANClsxMF0gIm1lZGl1bSBkaXZlcnMiOg0KQ3JhYmVhdGVyIFNlYWxzIC0gKFByZWZlcnJlZCB0ZW1wZXJhdHVyZSAoUmVmLiAxMTU5NjkpOiAtMC40IC0gMSwgbWVhbiAwLjEgKGJhc2VkIG9uIDkzOTcgY2VsbHMpKQ0KUm9zcyBzZWFscyAoUHJlZmVycmVkIHRlbXBlcmF0dXJlIChSZWYuIDExNTk2OSk6IC0xLjggLSAxLjEsIG1lYW4gLTEuNSAoYmFzZWQgb24gMjExMCBjZWxscykpOw0KV2VkZGVsbCBzZWFscyAoUHJlZmVycmVkIHRlbXBlcmF0dXJlIChSZWYuIDExNTk2OSk6IC0xLjggLSAxLCBtZWFuIC0xLjYgKGJhc2VkIG9uIDYwMjYgY2VsbHMpKTsNCkhvdXJnbGFzcyBkb2xwaGluIChQcmVmZXJyZWQgdGVtcGVyYXR1cmUgKFJlZi4gMTE1OTY5KTogMC4xIC0gMiwgbWVhbiAwLjkgKGJhc2VkIG9uIDExMjIyIGNlbGxzKSkgIyBOb3QgaW5jbHVkZWQgaW4gdGhlIGJpb21hc3MNCktpbmcgcGVuZ3VpbiAobm8gZGF0YSBvbiBzZWFsaWZlYmFzZSkNCkVtcGVyb3IgcGVuZ3VpbiAobm8gZGF0YSBvbiBzZWFsaWZlYmFzZSkNClsxMV0ibGFyZ2UgZGl2ZXJzIiAtIFNvdXRoZXJuIGVsZXBoYW50IHNlYWxzIG9ubHkgaW4gdGhpcyBncm91cCBub3cgdGhhdCBTcGVybSB3aGFsZXMgYXJlIGFsc28gc2VwZXJhdGVkICAgICAgICAgDQpbMTJdIm1pbmtlIHdoYWxlcyIgICAgICAgICAgICAgDQpbMTNdIm9yY2EiICAgICAgICAgICAgICAgICAgICAgDQpbMTRdInNwZXJtIHdoYWxlcyIgICAgICAgICAgICAgDQpbMTVdImJhbGVlbiB3aGFsZXMiIA0KDQpgYGB7cn0NCmdyb3Vwc19maW5hbCR0ZW1wX21pbiA8LSBjKC0xLjgsICMgZXVwaGF1c2lpZHMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC0yLCAjIHNhbHBzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLTIsICMgbWVzb3BlbGFnaWMgZmlzaGVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLTIsICMgYmF0aHlwZWxhZ2ljIGZpc2hlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0xLCAjICJzaGVsZiBhbmQgY29hc3RhbCBmaXNoZXMiIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAuMiwgIyAiZmx5aW5nIGJpcmRzIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0wLjQsICMgInNtYWxsIGRpdmVycyIgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLTAuOCwgIyAic3F1aWRzIiAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0yLCAjICJ0b290aGZpc2hlcyIgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0xLjksICMgImxlb3BhcmQgc2VhbHMiICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtMC40LCAjICJtZWRpdW0gZGl2ZXJzIiAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAuMSwgIyAibGFyZ2UgZGl2ZXJzIiAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjIsICMgIm1pbmtlIHdoYWxlcyIgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC4zLCAjICJvcmNhIiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAuMywgIyAic3Blcm0gd2hhbGVzIiAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjIpICMgImJhbGVlbiB3aGFsZXMiDQoNCmdyb3Vwc19maW5hbCR0ZW1wX21heCA8LSBjKDEuNiwgIyBldXBoYXVzaWlkcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgNSwgI3NhbHBzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNSwgIyBtZXNvcGVsYWdpYyBmaXNoZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA1LCAjIGJhdGh5cGVsYWdpYyBmaXNoZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA1LCAjICJzaGVsZiBhbmQgY29hc3RhbCBmaXNoZXMiIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDE4LjIsICMgImZseWluZyBiaXJkcyINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAjICJzbWFsbCBkaXZlcnMiICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEuMSwgIyAic3F1aWRzIiAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDUsICMgInRvb3RoZmlzaGVzIiAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMS40LCAjICJsZW9wYXJkIHNlYWxzIiAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwgIyAibWVkaXVtIGRpdmVycyIgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLjYsICMgImxhcmdlIGRpdmVycyIgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNywgIyAibWlua2Ugd2hhbGVzIiAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxMy4xLCAjICJvcmNhIiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDMuOCwgIyAic3Blcm0gd2hhbGVzIiAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxMC4yKSAjICJiYWxlZW4gd2hhbGVzIg0KYGBgDQoNCg0KYGBge3J9DQpnbGltcHNlKGdyb3Vwc19maW5hbCkNCmhlYWQoZ3JvdXBzX2ZpbmFsKQ0KYGBgDQpDcmVhdGUgcGFyYW1zIHRvIGdldCB3IHZhbHVlcw0KYGBge3J9DQpwYXJhbXMgPC0gbmV3TXVsdGlzcGVjaWVzUGFyYW1zKHNwZWNpZXNfcGFyYW1zID0gZ3JvdXBzX2ZpbmFsLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rpb24gPSB0aGV0YV9maW5hbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGthcHBhID0gMTAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdfcHBfY3V0b2ZmID0gMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5fd19wcCA9IDFlLTE0KQ0KDQojIHNhdmVSRFMocGFyYW1zLCAiYmFzZV9wYXJhbXMucmRzIikNCmBgYA0KDQpTZXQgdXAgdGltZSBzdGVwczoNCmBgYHtyfQ0KIyB0aW1lX3N0ZXBzIDwtIHNlcSgwLDYwMCwxKQ0KIyAjIEkgcmFuIGludG8gdHJvdWJsZSB1c2luZyBhbnkgdGltZSBzdGVwcyB0aGF0IGRpZG4ndCBzdGFydCB3aXRoIDAuDQojICMgSSBhbHNvIGhhZCB0cm91YmxlIHVzaW5nIGZyYWN0aW9uYWwgdGltZSBzdGVwcy4gIA0KIyAjIFNvLCB3aGF0J3MgaGVyZSBhcyB5ZWFyIGlzIHJlYWxseSBhIG1vbnRoLiAgDQojICMgU3VnZ2VzdGlvbnMgZm9yIGEgYmV0dGVyIHNvbHV0aW9uIHdlbGNvbWUNCmBgYA0KDQpTZXQgdXAgdGhlIHJlc291cmNlOg0KYGBge3J9DQojICMgTG9hZCByZXNvdXJjZSBzcGVjdHJhIA0KIyAjIE5vdGU6IFlvdSBtYXkgbmVlZCB0byB1cGRhdGUgdGhpcyBwYXRoDQojIGlzaW1pcF9wbGFua3RvbiA8LSByZWFkLnRhYmxlKCJHRkRMX3Jlc291cmNlX3NwZWN0cmEuZGF0IikNCiMgaXNpbWlwX3BsYW5rdG9uIDwtIGFzKGlzaW1pcF9wbGFua3RvbiwgIm1hdHJpeCIpDQojIHNpemVzIDwtIG5hbWVzKHBhcmFtc0Bpbml0aWFsX25fcHApDQojIG5fcHBfYXJyYXkgPC0gYXJyYXkoTkEsIGRpbSA9IGMobGVuZ3RoKHRpbWVfc3RlcHMpLCBsZW5ndGgoc2l6ZXMpKSwgZGltbmFtZXMgPSBsaXN0KHRpbWUgPSB0aW1lX3N0ZXBzLCB3ID0gc2l6ZXMpKQ0KIyAjIEZpbGwgYXJyYXkNCiMgIyBOZWVkIGFuIGV4dHJhIHRpbWUgc3RlcCBwcmVjZWRpbmcgdGhlIHNpbXVsYXRpb24NCiMgbl9wcF9hcnJheVsxLF0gPC0gaXNpbWlwX3BsYW5rdG9uWzEsXQ0KIyBmb3IgKHQgaW4gc2VxKDEsbGVuZ3RoKHRpbWVfc3RlcHMpIC0gMSwxKSkgew0KIyAgIG5fcHBfYXJyYXlbdCArIDEsXSA8LSBpc2ltaXBfcGxhbmt0b25bdCxdDQojIH0NCmBgYA0KDQpTZXQgdXAgdGVtcGVyYXR1cmUtcmVsYXRlZCBpbmZvcm1hdGlvbjoNCmBgYHtyfQ0KIyAjIExvYWQgb2NlYW4gdGVtcCBhcnJheQ0KIyAjIE5vdGU6IFlvdSBtYXkgbmVlZCB0byB1cGRhdGUgdGhpcyBwYXRoDQojIG9jZWFuX3RlbXAgPC0gcmVhZC50YWJsZSgiQ2xpbWF0ZUZvcmNpbmcvR0ZETF9vY2Vhbl90ZW1wX3JlYWxtX2FycmF5LmRhdCIpDQojIG9jZWFuX3RlbXAgPC0gYXMob2NlYW5fdGVtcCwgIm1hdHJpeCIpDQojIHIgPC0gY29sbmFtZXMob2NlYW5fdGVtcCkNCiMgb2NlYW5fdGVtcF9hcnJheSA8LSBhcnJheShOQSwgZGltID0gYyhsZW5ndGgodGltZV9zdGVwcyksIGxlbmd0aChyKSksIGRpbW5hbWVzID0gbGlzdCh0aW1lID0gdGltZV9zdGVwcywgcmVhbG1fbmFtZXMgPSByKSkNCiMgb2NlYW5fdGVtcF9hcnJheVsxLF0gPC0gb2NlYW5fdGVtcFsxLF0NCiMgZm9yICh0IGluIHNlcSgxLGxlbmd0aCh0aW1lX3N0ZXBzKSAtIDEsIDEpKSB7DQojICAgb2NlYW5fdGVtcF9hcnJheVt0ICsgMSxdIDwtIG9jZWFuX3RlbXBbdCxdDQojIH0NCg0KYGBgDQoNCg0KTm93IHdlIHdpbGwgc2V0IHVwIHRoZSBgdmVydGljYWxfbWlncmF0aW9uYCBhcnJheS4gV2UnbGwgYXNzdW1lIHRoYXQ6DQoNCg0KYGBge3J9DQpncm91cHNfVk1BIDwtIGdyb3Vwc19maW5hbA0KDQpyZWFsbV9uYW1lcyA8LSBjKCJ1cHBlcjUwbSIsImJvdHRvbSIsIkRWTV9kYXkiLCJEVk1fbmlnaHQiLCJvbnRvZ2VuZXRpYyIsImRpdmluZyIpDQpzcGVjaWVzX25hbWVzIDwtIGFzLmNoYXJhY3Rlcihncm91cHNfVk1BJHNwZWNpZXMpDQpzaXplcyA8LSBwYXJhbXNAdw0KDQojIENyZWF0ZSB0aGUgdmVydGljYWwgbWlncmF0aW9uIGFycmF5IGFuZCBmaWxsIGl0DQp2ZXJ0aWNhbF9taWdyYXRpb25fYXJyYXkgPC0gYXJyYXkoMCwgZGltID0gKGMobGVuZ3RoKHJlYWxtX25hbWVzKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoKHNwZWNpZXNfbmFtZXMpLCBsZW5ndGgoc2l6ZXMpKSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChyZWFsbSA9IHJlYWxtX25hbWVzLCBzcCA9IHNwZWNpZXNfbmFtZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHcgPSBzaWduaWYoc2l6ZXMsMykpKSAjIHJlYWxtIHggc3BlY2llcyB4IHNpemUNCg0KdXBwIDwtIHdoaWNoKHJlYWxtX25hbWVzID09ICJ1cHBlcjUwbSIpICMgMCAtIDUwbSBhdmVyYWdlDQpidG0gPC0gd2hpY2gocmVhbG1fbmFtZXMgPT0gImJvdHRvbSIpICMgc2VhIGZsb29yDQpEVk1kIDwtIHdoaWNoKHJlYWxtX25hbWVzID09ICJEVk1fZGF5IikgIyAyMDAgLSA1MDBtIGF2ZXJhZ2UNCkRWTW4gPC0gd2hpY2gocmVhbG1fbmFtZXMgPT0gIkRWTV9uaWdodCIpICMgMCAtIDEwMG0gYXZlcmFnZQ0Kb250IDwtIHdoaWNoKHJlYWxtX25hbWVzID09ICJvbnRvZ2VuZXRpYyIpICMgZGVlcGVyIGFmdGVyIHdfbWF0DQpkaXZlIDwtIHdoaWNoKHJlYWxtX25hbWVzID09ICJkaXZpbmciKSAjIGV2ZW5seSBzcHJlYWQgYWNyb3NzIGVudGlyZSByZWFsbQ0KDQojIFNldCBhbGwgc2l6ZXMgYmVsb3cgd19tYXQgZm9yIGV1cGhhdXNpaWRzIHRvICJ1cHBlcjUwbSIgYW5kIGFsbCBzaXplcyBhYm92ZSB3X21hdCB0byAiYm90dG9tDQpzcEEgPC0gd2hpY2goc3BlY2llc19uYW1lcyA9PSAiZXVwaGF1c2lpZHMiKQ0KdmVydGljYWxfbWlncmF0aW9uX2FycmF5W3VwcCwgc3BBLCBzaXplcyA8IHBhcmFtc0BzcGVjaWVzX3BhcmFtcyR3X21hdFtzcEFdXSA8LSAxDQp2ZXJ0aWNhbF9taWdyYXRpb25fYXJyYXlbYnRtLCBzcEEsIHNpemVzID49IHBhcmFtc0BzcGVjaWVzX3BhcmFtcyR3X21hdFtzcEFdXSA8LSAxDQoNCiMgU2V0IGFsbCBzaXplcyBiZWxvdyB3X21hdCBmb3IgZXVwaGF1c2lpZHMgdG8gInVwcGVyNTBtIiBhbmQgYWxsIHNpemVzIGFib3ZlIHdfbWF0IHRvICJib3R0b20NCnNwUyA8LSB3aGljaChzcGVjaWVzX25hbWVzID09ICJzYWxwcyIpDQp2ZXJ0aWNhbF9taWdyYXRpb25fYXJyYXlbRFZNZCwgc3BTLCBdIDwtIDAuNQ0KdmVydGljYWxfbWlncmF0aW9uX2FycmF5W0RWTW4sIHNwUywgXSA8LSAwLjUNCg0KIyBIYXZlIG1lc29wZWxhZ2ljIGZpc2hlcyBzcGxpdCBpdHMgdGltZSBlcXVhbGx5IHVzaW5nIERWTQ0Kc3BCIDwtIHdoaWNoKHNwZWNpZXNfbmFtZXMgPT0gIm1lc29wZWxhZ2ljIGZpc2hlcyIpDQp2ZXJ0aWNhbF9taWdyYXRpb25fYXJyYXlbRFZNZCwgc3BCLCBdIDwtIDAuNQ0KdmVydGljYWxfbWlncmF0aW9uX2FycmF5W0RWTW4sIHNwQiwgXSA8LSAwLjUNCg0KIyBTZXQgYWxsIHNpemVzIGJlbG93IHdfbWF0IGZvciBiYXRoeXBlbGFnaWMgZmlzaGVzIHRvICJ1cHBlcjUwbSIgYW5kIHNwbGl0IHRpbWUgZXF1YWxseSB1c2luZyBEVk0gZm9yIHNpemVzIGFib3ZlIHdfbWF0DQpzcEMgPC0gd2hpY2goc3BlY2llc19uYW1lcyA9PSAiYmF0aHlwZWxhZ2ljIGZpc2hlcyIpDQp2ZXJ0aWNhbF9taWdyYXRpb25fYXJyYXlbdXBwLCBzcEMsIHNpemVzIDwgcGFyYW1zQHNwZWNpZXNfcGFyYW1zJHdfbWF0W3NwQ11dIDwtIDENCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVtEVk1kLCBzcEMsIHNpemVzID49IHBhcmFtc0BzcGVjaWVzX3BhcmFtcyR3X21hdFtzcENdXSA8LSAwLjUNCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVtEVk1uLCBzcEMsIHNpemVzID49IHBhcmFtc0BzcGVjaWVzX3BhcmFtcyR3X21hdFtzcENdXSA8LSAwLjUNCg0KIyBTZXQgYWxsIHNpemVzIGJlbG93IHdfbWF0IGZvciBzaGVsZiBhbmQgY29hc3RhbCBmaXNoZXMgdG8gInVwcGVyNTBtIiBhbmQgYWxsIHNpemVzIGFib3ZlIHdfbWF0IHRvICJib3R0b20iDQpzcEQgPC0gd2hpY2goc3BlY2llc19uYW1lcyA9PSAic2hlbGYgYW5kIGNvYXN0YWwgZmlzaGVzIikNCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVt1cHAsIHNwRCwgc2l6ZXMgPCBwYXJhbXNAc3BlY2llc19wYXJhbXMkd19tYXRbc3BEXV0gPC0gMQ0KdmVydGljYWxfbWlncmF0aW9uX2FycmF5W2J0bSwgc3BELCBzaXplcyA+PSBwYXJhbXNAc3BlY2llc19wYXJhbXMkd19tYXRbc3BEXV0gPC0gMQ0KDQojIEhhdmUgZmx5aW5nIGJpcmRzIHNwZW5kIGFsbCB0aGVpciB0aW1lIGluICJkaXZpbmciDQpzcEUgPC0gd2hpY2goc3BlY2llc19uYW1lcyA9PSAiZmx5aW5nIGJpcmRzIikNCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVtkaXZlLCBzcEUsIF0gPC0gMQ0KDQojIEhhdmUgc21hbGwgZGl2ZXJzIHNwZW5kIGFsbCB0aGVpciB0aW1lIGluICJkaXZpbmciDQpzcEYgPC0gd2hpY2goc3BlY2llc19uYW1lcyA9PSAic21hbGwgZGl2ZXJzIikNCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVtkaXZlLCBzcEYsIF0gPC0gMQ0KDQojIFNldCBhbGwgc2l6ZXMgYmVsb3cgd19tYXQgZm9yIHNxdWlkcyB0byAidXBwZXI1MG0iIGFuZCBzcGxpdCB0aW1lIGVxdWFsbHkgdXNpbmcgRFZNIGZvciBzaXplcyBhYm92ZSB3X21hdA0Kc3BHIDwtIHdoaWNoKHNwZWNpZXNfbmFtZXMgPT0gInNxdWlkcyIpDQp2ZXJ0aWNhbF9taWdyYXRpb25fYXJyYXlbdXBwLCBzcEcsIHNpemVzIDwgcGFyYW1zQHNwZWNpZXNfcGFyYW1zJHdfbWF0W3NwR11dIDwtIDENCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVtEVk1kLCBzcEcsIHNpemVzID49IHBhcmFtc0BzcGVjaWVzX3BhcmFtcyR3X21hdFtzcEddXSA8LSAwLjUNCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVtEVk1uLCBzcEcsIHNpemVzID49IHBhcmFtc0BzcGVjaWVzX3BhcmFtcyR3X21hdFtzcEddXSA8LSAwLjUNCg0KIyBTZXQgYWxsIHNpemVzIGJlbG93IHdfbWF0IGZvciB0b290aGZpc2hlcyB0byAidXBwZXI1MG0iIGFuZCBhbGwgc2l6ZXMgYWJvdmUgd19tYXQgdG8gImJvdHRvbQ0Kc3BIIDwtIHdoaWNoKHNwZWNpZXNfbmFtZXMgPT0gInRvb3RoZmlzaGVzIikNCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVt1cHAsIHNwSCwgc2l6ZXMgPCBwYXJhbXNAc3BlY2llc19wYXJhbXMkd19tYXRbc3BIXV0gPC0gMQ0KdmVydGljYWxfbWlncmF0aW9uX2FycmF5W2J0bSwgc3BILCBzaXplcyA+PSBwYXJhbXNAc3BlY2llc19wYXJhbXMkd19tYXRbc3BIXV0gPC0gMQ0KDQojIEhhdmUgbGVvcGFyZCBzZWFscyBzcGVuZCBhbGwgdGhlaXIgdGltZSBpbiAiZGl2aW5nIg0Kc3BJIDwtIHdoaWNoKHNwZWNpZXNfbmFtZXMgPT0gImxlb3BhcmQgc2VhbHMiKQ0KdmVydGljYWxfbWlncmF0aW9uX2FycmF5W2RpdmUsIHNwSSwgXSA8LSAxDQoNCiMgSGF2ZSBtZWRpdW0gZGl2ZXJzIHNwZW5kIGFsbCB0aGVpciB0aW1lIGluICJkaXZpbmciDQpzcEogPC0gd2hpY2goc3BlY2llc19uYW1lcyA9PSAibWVkaXVtIGRpdmVycyIpDQp2ZXJ0aWNhbF9taWdyYXRpb25fYXJyYXlbZGl2ZSwgc3BKLCBdIDwtIDENCg0KIyBIYXZlIGxhcmdlIGRpdmVycyBzcGVuZCBhbGwgdGhlaXIgdGltZSBpbiAiZGl2aW5nIg0Kc3BLIDwtIHdoaWNoKHNwZWNpZXNfbmFtZXMgPT0gImxhcmdlIGRpdmVycyIpDQp2ZXJ0aWNhbF9taWdyYXRpb25fYXJyYXlbZGl2ZSwgc3BLLCBdIDwtIDENCg0KIyBIYXZlIG1pbmtlIHdoYWxlcyBzcGVuZCBhbGwgdGhlaXIgdGltZSBpbiAiZGl2aW5nIg0Kc3BMIDwtIHdoaWNoKHNwZWNpZXNfbmFtZXMgPT0gIm1pbmtlIHdoYWxlcyIpDQp2ZXJ0aWNhbF9taWdyYXRpb25fYXJyYXlbZGl2ZSwgc3BMLCBdIDwtIDENCg0KIyBIYXZlIG9yY2Egc3BlbmQgYWxsIHRoZWlyIHRpbWUgaW4gImRpdmluZyINCnNwTSA8LSB3aGljaChzcGVjaWVzX25hbWVzID09ICJvcmNhIikNCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVtkaXZlLCBzcE0sIF0gPC0gMQ0KDQojIEhhdmUgc3Blcm0gd2hhbGVzIHNwZW5kIGFsbCB0aGVpciB0aW1lIGluICJkaXZpbmciDQpzcE4gPC0gd2hpY2goc3BlY2llc19uYW1lcyA9PSAic3Blcm0gd2hhbGVzIikNCnZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheVtkaXZlLCBzcE4sIF0gPC0gMQ0KDQojIEhhdmUgYmFsZWVuIHdoYWxlcyBzcGVuZCBhbGwgdGhlaXIgdGltZSBpbiAiZGl2aW5nIg0Kc3BPIDwtIHdoaWNoKHNwZWNpZXNfbmFtZXMgPT0gImJhbGVlbiB3aGFsZXMiKQ0KdmVydGljYWxfbWlncmF0aW9uX2FycmF5W2RpdmUsIHNwTywgXSA8LSAxDQoNCmBgYA0KDQoNClVzaW5nIHRoZSBzYW1lIHNjZW5hcmlvLCBldmVyeXRoaW5nIGlzIHByZXNlbnQgaW4gYWxsIGxheWVycywgc28gdGhlIGBleHBvc3VyZWAgYXJyYXkgaXMgYWxsIDFzLg0KDQpgYGB7cn0NCmV4cG9zdXJlX2FycmF5IDwtIGFycmF5KDEsIGRpbSA9IChjKGxlbmd0aChyZWFsbV9uYW1lcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgoc3BlY2llc19uYW1lcykpKSwgDQogICAgICAgICAgICAgICAgICAgICAgICBkaW1uYW1lcyA9IGxpc3QgKHJlYWxtID0gcmVhbG1fbmFtZXMsIHNwID0gc3BlY2llc19uYW1lcykpICNyZWFsbSB4IHNwZWNpZXMNCg0KZXhwb3N1cmVfYXJyYXkNCmBgYA0KDQpDcmVhdGUgdGhlIHRlbXBlcmF0dXJlcyBmb3IgZWFjaCByZWFsbS4NCg0KDQpgYGB7cn0NCiMgQ3JlYXRlIHRlbXBlcmF0dXJlIGFycmF5IGFuZCBmaWxsIGl0DQp0aW1lcyA8LSAwOjUwMA0Kb2NlYW5fdGVtcF9hcnJheSA8LSBhcnJheShOQSwgZGltID0gYyhsZW5ndGgodGltZXMpLCBsZW5ndGgocmVhbG1fbmFtZXMpKSwgDQogICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdCh0aW1lID0gdGltZXMsIHJlYWxtID0gcmVhbG1fbmFtZXMpKQ0KdGVtcF9pbmMgPC0gMA0KZm9yIChpIGluIDE6NTAxKSB7DQogIG9jZWFuX3RlbXBfYXJyYXlbaSxdIDwtIGMoMiArIHRlbXBfaW5jLCAtMiArIHRlbXBfaW5jLCAyICsgdGVtcF9pbmMsIC0xICsgdGVtcF9pbmMsIC0xICsgdGVtcF9pbmMsIC0xICsgdGVtcF9pbmMpDQogIHRlbXBfaW5jIDwtIHRlbXBfaW5jICsgMC4wMQ0KfQ0KDQpgYGANCg0KDQpDcmVhdGUgYSBkeW5hbWljLCB0aW1lLXZhcnlpbmcgcmVzb3VyY2Ugc3BlY3RyYS4NCg0KYGBge3J9DQoNCnggPC0gcGFyYW1zQHdfZnVsbA0Kc2xvcGUgPC0gLTENCmludGVyY2VwdCA8LSAtNQ0KDQojIENyZWF0ZSByZXNvdXJjZSBhcnJheSBhbmQgZmlsbCBpdA0Kbl9wcF9hcnJheSA8LSBhcnJheShOQSwgZGltID0gYyhsZW5ndGgodGltZXMpLCBsZW5ndGgoeCkpLCANCiAgICAgICAgICAgICAgICAgICAgZGltbmFtZXMgPSBsaXN0KHRpbWUgPSB0aW1lcywgdyA9IHNpZ25pZih4LDMpKSkNCg0KZm9yIChpIGluIDE6NTAxKSB7DQogICMgQWRkIHNvbWUgbm9pc2UgYXJvdW5kIHRoZSBzbG9wZSBhbmQgaW50ZXJjZXB0IGFzIHdlIGZpbGwgdGhlIGFycmF5DQogIG5fcHBfYXJyYXlbaSxdIDwtIChzbG9wZSAqIHJ1bmlmKDEsIG1pbiA9IDAuOTUsIG1heCA9IDEuMDUpICogbG9nMTAoeCkpICsgDQogICAgICAgICAgICAgICAgICAgIChpbnRlcmNlcHQgKiBydW5pZigxLCBtaW4gPSAwLjk1LCBtYXggPSAxLjA1KSkNCn0NCg0KDQpgYGANCg0KIyMgUnVubmluZyBhIHNjZW5hcmlvDQoNClRoZSBgdXBncmFkZVRoZXJQYXJhbXNgIGZ1bmN0aW9uIGNvbWJpbmVzIGEgc3RhbmRhcmQgYG1pemVyUGFyYW1zYCBvYmplY3Qgd2l0aCB0aGUgdGhlck1pemVyIG9iamVjdHMgZGVzY3JpYmVkIGFib3ZlLg0KDQpgYGB7cn0NCnNvX3RoZXJtX21vZGVsIDwtICB1cGdyYWRlVGhlclBhcmFtcyhwYXJhbXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGVtcF9taW4gPSB0ZW1wX21pbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRlbXBfbWF4ID0gdGVtcF9tYXgsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgb2NlYW5fdGVtcF9hcnJheSA9IG9jZWFuX3RlbXBfYXJyYXksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbl9wcF9hcnJheSA9IG5fcHBfYXJyYXksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheSA9IHZlcnRpY2FsX21pZ3JhdGlvbl9hcnJheSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHBvc3VyZV9hcnJheSA9IGV4cG9zdXJlX2FycmF5LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXJvYmljX2VmZmVjdCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGFib2xpc21fZWZmZWN0ID0gVFJVRSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpgYGANCg0KTGV0J3MgbG9vayBhdCB0aGUgdGhlcm1hbCB0b2xlcmFuY2VzIG9mIGFsbCB0aGUgc3BlY2llcyBpbiB0aGUgbW9kZWwuDQoNCmBgYHtyfQ0KdGhlck1pemVyOjpwbG90VGhlclBlcmZvcm1hbmNlKHNvX3RoZXJtX21vZGVsKQ0KIyBwbG90VGhlcm1QZXJmb3JtYW5jZShzb190aGVybV9tb2RlbCkNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc192MDAgPC0gc3RlYWR5KHNvX3RoZXJtX21vZGVsKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmJveC5wYXJhbXMgPC0gc29fdGhlcm1fbW9kZWwNCg0KYm94LnBhcmFtc0BzcGVjaWVzX3BhcmFtcyRwcG1yX21pbltib3gucGFyYW1zQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gImJhbGVlbiB3aGFsZXMiXSAgPC0gMWU1DQpib3gucGFyYW1zQHNwZWNpZXNfcGFyYW1zJHBwbXJfbWF4W2JveC5wYXJhbXNAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAiYmFsZWVuIHdoYWxlcyJdIDwtNWU3DQpib3gucGFyYW1zQHNwZWNpZXNfcGFyYW1zJHByZWRfa2VybmVsX3R5cGVbYm94LnBhcmFtc0BzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJiYWxlZW4gd2hhbGVzIl0gPC0gImJveCINCmBgYA0KDQoNCmBgYHtyfQ0Kc3BlY2llc19wYXJhbXMoYm94LnBhcmFtcykgfD4gZHBseXI6OnNlbGVjdCh3X21pbiwgd19tYXQsIHdfbWF4KQ0KYGBgDQoNCkFkanVzdCBgd19tYXRgIHZhbHVlcyB0aGF0IHdlcmUgY2hhbmdlZCBieSBkZWZhdWx0IGluIGBuZXdNdWx0aXNwZWNpZXNQYXJhbXNgDQpgYGB7cn0NCnBhcmFtc192MSA8LSBib3gucGFyYW1zDQoNCnBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21hdFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAibGFyZ2UgZGl2ZXJzIl0gIDwtIHBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21heFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAibGFyZ2UgZGl2ZXJzIl0gKiAwLjkNCnBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21hdFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAibWlua2Ugd2hhbGVzIl0gIDwtIHBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21heFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAibWlua2Ugd2hhbGVzIl0gKiAwLjkNCnBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21hdFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAib3JjYSJdICA8LSBwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkd19tYXhbcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gIm9yY2EiXSAqIDAuOQ0KcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJHdfbWF0W3BhcmFtc192MUBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJzcGVybSB3aGFsZXMiXSAgPC0gcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJHdfbWF4W3BhcmFtc192MUBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJzcGVybSB3aGFsZXMiXSAqIDAuOQ0KDQpwYXJhbXNfdjEgPC0gc2V0UGFyYW1zKHBhcmFtc192MSkNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX3YyIDwtIHBhcmFtc192MQ0KDQpwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkd19taW5bcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gInNtYWxsIGRpdmVycyJdICA8LSBwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkd19tYXRbcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gInNtYWxsIGRpdmVycyJdICogMC44NQ0KcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHdfbWluW3BhcmFtc192MkBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJsZW9wYXJkIHNlYWxzIl0gIDwtIHBhcmFtc192MkBzcGVjaWVzX3BhcmFtcyR3X21hdFtwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAibGVvcGFyZCBzZWFscyJdICogMC44NQ0KDQpwYXJhbXNfdjIgPC0gc2V0UGFyYW1zKHBhcmFtc192MikNCmBgYA0KDQpGaXJzdCBzaW11bGF0aW9uIHVzaW5nIHJhdyBwYXJhbSB2YWx1ZXMNCk5lZWQgdG8gYWRqdXN0IHN0YXJ0aW5nIFJtYXggdmFsdWVzLiBVc2UgSnVsaWEncyBxdWljayBjYWxpYnJhdGlvbiB1c2luZyBrYXBwYSAoYWx0aG91Z2ggc3RhcnRpbmcga2FwcGEgaXMgYSB0b3RhbCBndWVzcyBhcyB3ZWxsKQ0KDQpgYGB7cn0NCnNwZWNpZXNfcGFyYW1zKHBhcmFtc192MikgfD4gZHBseXI6OnNlbGVjdCh3X21pbiwgd19tYXQsIHdfbWF4KQ0KYGBgDQoNCg0KYGBge3J9DQpwYXJhbXNfZ3Vlc3NlZCA8LSBwYXJhbXNfdjINCg0KcGFyYW1zX2d1ZXNzZWRAc3BlY2llc19wYXJhbXMkUl9tYXggPC0gcGFyYW1zX2d1ZXNzZWRAcmVzb3VyY2VfcGFyYW1zJGthcHBhKnBhcmFtc19ndWVzc2VkQHNwZWNpZXNfcGFyYW1zJHdfbWF4Xi0xLjUNCg0KcGFyYW1zX2d1ZXNzZWQgPC0gc2V0UGFyYW1zKHBhcmFtc19ndWVzc2VkKQ0KDQpzaW1fZ3Vlc3NlZCA8LSBwcm9qZWN0KHBhcmFtc19ndWVzc2VkLCBlZmZvcnQ9MCkNCg0KcGxvdChzaW1fZ3Vlc3NlZCkNCnBsb3RseUZlZWRpbmdMZXZlbChzaW1fZ3Vlc3NlZCkNCnBsb3RseUJpb21hc3Moc2ltX2d1ZXNzZWQpDQojIHBsb3REaWV0KHNpbV9ndWVzc2VkKQ0KcGxvdFNwZWN0cmEoc2ltX2d1ZXNzZWQpDQpgYGANCkFwZXggcHJlZGF0b3JzIGhhdmUgdGhlIG1vc3QgZGl2ZXJzZSBkaWV0IGFuZCBhcmUgb25seSBwcmV5aW5nIHVwb24gZHluYW1pYyBncm91cHMuIEhvd2V2ZXIsIHRoaXMgbWVhbnMgdGhleSBkb24ndCBoYXZlIGVub3VnaCB0byBlYXQuIFdlIGNhbiBlaXRoZXIgb3BlbiB1cCByZXNvdXJjZXMgYXZhaWxhYmxlIHRvIHRoZW0sIGFsdGhvdWdoIHRoZSBlbXBpcmljYWwgb2JzZXJ2YXRpb25zIHN1Z2dlc3QgdGhhdCB0aGV5IHNob3VsZCBiZSBlYXRpbmcgdGhlIGxhcmdlciBpbnZpZHVhbHMgb2YgZ3JvdXBzIGxpa2UgZGl2ZXJzLiBTbywgaW5zdGVhZCBvZiBpbmNyZWFzaW5nIGBiZXRhYCBvciBpbmNyZWFzaW5nIHRoZSB3aWR0aCBvZiB0aGVpciBmZWVkaW5nIGtlcm5lbCwgd2Ugd2lsbCB0cnkgdG8gYWRkIGEgbmV3IHJlc291cmNlIHNwZWN0cnVtIHRoYXQgb25seSBhcGV4IHByZWRhdG9ycyBjYW4gYWNjZXNzIHRvIGFpZCB0aGVpciBncm93dGggYW5kIHJlcHJvZHVjdGlvbi4gSWYgd2UgY2FuIHJlYWNoIGEgc3RlYWR5IHN0YXRlIGluIHRoaXMgZmFzaGlvbiwgdGhlbiB3ZSBjYW4gcmVtb3ZlIHRoZSBhZGRpdGlvbmFsIHJlc291cmNlIHdpdGggZnVydGhlciBjYWxpYnJhdGlvbiBlZmZvcnRzLg0KDQoNCmBgYHtyfQ0KcGFyYW1zX3YwMCA8LSBzdGVhZHkocGFyYW1zX2d1ZXNzZWQpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KG1pemVyRXhwZXJpbWVudGFsKQ0KYGBgDQoNCg0KYGBge3J9DQojIHBhcmFtc19nX3YyIDwtIG1pemVyRXhwZXJpbWVudGFsOjpzY2FsZURvd25CYWNrZ3JvdW5kKHBhcmFtc19ndWVzc2VkLDEwMDAwMCkNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc19ndWVzc2VkIDwtIHBhcmFtc19ndWVzc2VkDQoNCnBhcmFtc19ndWVzc2VkQHNwZWNpZXNfcGFyYW1zJGJldGFbYm94LnBhcmFtc0BzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJvcmNhIl0gIDwtIDEwMA0KIyBwYXJhbXNfZ3Vlc3NlZEBzcGVjaWVzX3BhcmFtcyRzaWdtYVtib3gucGFyYW1zQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gIm9yY2EiXSA8LSAyLjUNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc192MDAgPC0gc3RlYWR5KHBhcmFtc19ndWVzc2VkKQ0KYGBgDQoNCg0KYGBge3J9DQpwYXJhbXNfdHVuZWRfdjEgPC0gbWl6ZXJFeHBlcmltZW50YWw6OnR1bmVQYXJhbXMocGFyYW1zX2d1ZXNzZWQpDQpgYGANCg0KDQoNCmBgYHtyfQ0KcGFyYW1zX2d1ZXNzZWRAc3BlY2llc19wYXJhbXMkc3BlY2llcw0KcGFyYW1zX2d1ZXNzZWRAc3BlY2llc19wYXJhbXMkUl9tYXgNCg0KDQpwYXJhbXNfdjEgPC0gcGFyYW1zX2d1ZXNzZWQNCg0KIyBwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkUl9tYXhbcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gIm9yY2EiXSA8LSBJbmYNCg0KIyBwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkZ2FtbWFbcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gIm9yY2EiXSA8LSBwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkZ2FtbWFbcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gIm9yY2EiXSAqIDUwDQoNCiMgcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJGdhbW1hW3BhcmFtc192MUBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJtaWNyb3pvb3BsYW5rdG9uIl0gPC0gcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJGdhbW1hW3BhcmFtc192MUBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJtaWNyb3pvb3BsYW5rdG9uIl0gKiAyDQoNCnBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyRnYW1tYVtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAiZmx5aW5nIGJpcmRzIl0gPC0gcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJGdhbW1hW3BhcmFtc192MUBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJmbHlpbmcgYmlyZHMiXSAqIDINCg0KYGBgDQoNCg0KYGBge3J9DQpwYXJhbXNfc3RlYWR5X3YxIDwtIHN0ZWFkeShwYXJhbXNfdHVuZWRfdjEpDQpgYGANCg0KDQpgYGB7cn0NCnBhcmFtc192MSA8LSBzZXRQYXJhbXMocGFyYW1zX3R1bmVkX3YxKQ0KDQpzaW1fZ3Vlc3NlZCA8LSBwcm9qZWN0KHBhcmFtc190dW5lZF92MSwgZWZmb3J0PTAsIHRfbWF4ID0gNTAwKQ0KDQpwbG90KHNpbV9ndWVzc2VkKQ0KcGxvdGx5QmlvbWFzcyhzaW1fZ3Vlc3NlZCkNCmBgYA0KDQoNClJlZmluZSBib3ggZmVlZGluZyBrZXJuZWwgZm9yIHRoZSBiYWxlZW4gd2hhbGVzDQptYXggcHBtciB2YWx1ZSBhcmUgYmFzZWQgb24gd19tYXggYmFsZWVuIHdoYWxlIGZlZWRpbmcgb24gd19taW4gZXVwaGF1c2lpZHMNCm1pbiBwcG1yIHZhbHVlIGJhc2VkIG9uIHdfbWluIGJhbGVlbiB3aGFsZSBmZWVkaW5nIG9uIHdfbWF4IGV1cGhhdXNpaWRzDQoNCmBgYHtyfQ0KcGFyYW1zX3YyIDwtIHBhcmFtc192MQ0KDQpwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkd19taW5bcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gImJhbGVlbiB3aGFsZXMiXQ0KcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHdfbWF4W3BhcmFtc192MkBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJiYWxlZW4gd2hhbGVzIl0NCg0KcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHdfbWluW3BhcmFtc192MkBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJldXBoYXVzaWlkcyJdDQpwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkd19tYXhbcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gImV1cGhhdXNpaWRzIl0NCmBgYA0KDQoNCg0KYGBge3J9DQojIDEuMDNlKzA4LzYuMzFlLTA1ICMgd19tYXggYmFsZWVuIHdoYWxlIGRpdmlkZWQgYnkgd19taW4gZXVwaGF1c2lpZHMNCiMgMjI1MDAwMC8zLjE2MjI3OCAjIHdfbWluIGJhbGVlbiB3aGFsZSBkaXZpZGVkIGJ5IHdfbWF4IGV1cGhhdXNpaWRzDQoNCnBhcmFtc192MkBzcGVjaWVzX3BhcmFtcyRwcG1yX21pbltwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAiYmFsZWVuIHdoYWxlcyJdICA8LSA3MTE1MTIuNA0KcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHBwbXJfbWF4W3BhcmFtc192MkBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJiYWxlZW4gd2hhbGVzIl0gPC0gMS42MzIzM2UrMTINCg0KIyBwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkcHBtcl9taW5bcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gImJhbGVlbiB3aGFsZXMiXSAgPC0gMWU1DQojIHBhcmFtc192MkBzcGVjaWVzX3BhcmFtcyRwcG1yX21heFtwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAiYmFsZWVuIHdoYWxlcyJdIDwtNWU3DQpwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkcHJlZF9rZXJuZWxfdHlwZVtwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAiYmFsZWVuIHdoYWxlcyJdIDwtICJib3giDQoNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX3YyIDwtIHNldFBhcmFtcyhwYXJhbXNfdjIpDQoNCnNpbV92MiA8LSBwcm9qZWN0KHBhcmFtc192MiwgZWZmb3J0PTAsIHRfbWF4ID0gNTAwKQ0KDQpwbG90KHNpbV92MikNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc190dW5lZCA8LSB0dW5lR3Jvd3RoKHBhcmFtc192MikNCmBgYA0KDQoNCmBgYHtyfQ0KbWl6ZXI6OnBsb3REaWV0KHBhcmFtc192MikNCmBgYA0KDQoNCmBgYHtyfQ0KIyBzYXZlUkRTKHBhcmFtc192MiwgInN0YWdlMV9zdGVhZHkucmRzIikgI3N0YWdlIDEgaXMgd2l0aCBiYWxlZW4gd2hhbGUgYm94IGtlcm5lbCwgYWRqdXN0ZWQgbWF0dXJhdGlvbiBzaXplcyBmb3IgbW9zdCBtYXJpbmUgbWFtbWFscyBhbmQgYSBiYWNrZ3JvdW5kIHJlc291cmNlIHdpdGggYSBsYXJnZSBtYXggc2l6ZQ0KDQpwYXJhbXNfdjIgPC0gcmVhZFJEUygic3RhZ2UxX3N0ZWFkeS5yZHMiKQ0KYGBgDQoNCk5vdyBJIHdpbGwgdHJ5IHRvIHJlZHVjZSB0aGUgbWF4IHNpemUgb2YgdGhlIHJlc291cmNlDQpgYGB7cn0NCnBhcmFtc192MyA8LSBwYXJhbXNfdjINCg0KcGFyYW1zX3YzQHJlc291cmNlX3BhcmFtcyR3X3BwX2N1dG9mZiAjIHN0YXJ0ZWQgd2l0aCAxMDAwMA0KDQpwYXJhbXNfdjNAcmVzb3VyY2VfcGFyYW1zJHdfcHBfY3V0b2ZmICA8LSAxMDANCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX3YzIDwtIHNldFBhcmFtcyhwYXJhbXNfdjMpDQoNCnNpbV92MyA8LSBwcm9qZWN0KHBhcmFtc192MywgZWZmb3J0PTAsIHRfbWF4ID0gMTAwMCkNCg0KcGxvdChzaW1fdjMpDQpgYGANCmBgYHtyfQ0KbWl6ZXI6OnBsb3REaWV0KHBhcmFtc192MykNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc192M19zdGVhZHkgPC0gc3RlYWR5KHBhcmFtc192MykNCnBhcmFtc192M190dW5lZCA8LSB0dW5lUGFyYW1zKHBhcmFtc192M19zdGVhZHkpDQpgYGANCg0KDQpgYGB7cn0NCnBhcmFtc192M190dW5lZEBzcGVjaWVzX3BhcmFtcyRlcmVwcm8NCnBhcmFtc192M190dW5lZEBzcGVjaWVzX3BhcmFtcyR3X21hdA0KcGFyYW1zX3YzX3R1bmVkQHNwZWNpZXNfcGFyYW1zJHdfbWF0MjUNCnBhcmFtc192M190dW5lZEByZXNvdXJjZV9wYXJhbXMkd19wcF9jdXRvZmYNCmBgYA0KDQpgYGB7cn0NCm1pemVyOjpwbG90RGlldChwYXJhbXNfdjNfdHVuZWQpDQpgYGANCg0KYGBge3J9DQpwYXJhbXNfdjQgPC0gdHVuZUdyb3d0aChwYXJhbXNfdjNfdHVuZWQpDQoNCnNpbV92NCA8LSBwcm9qZWN0KHBhcmFtc192NCwgZWZmb3J0PTAsIHRfbWF4ID0gMTAwMCkNCg0KcGxvdChzaW1fdjQpDQpwbG90bHlCaW9tYXNzKHNpbV92NCkNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX3Y1IDwtIHR1bmVHcm93dGgocGFyYW1zX3Y0KQ0KDQpzaW1fdjUgPC0gcHJvamVjdChwYXJhbXNfdjUsIGVmZm9ydD0wLCB0X21heCA9IDEwMDApDQoNCnBsb3Qoc2ltX3Y1KQ0KcGxvdGx5QmlvbWFzcyhzaW1fdjUpDQpgYGANCg0KDQoNCmBgYHtyfQ0KcGFyYW1zX3Y1X3N0ZWFkeSA8LSBzdGVhZHkocGFyYW1zX3Y1KQ0KcGFyYW1zX3Y1X3R1bmVkIDwtIHR1bmVQYXJhbXMocGFyYW1zX3Y1X3N0ZWFkeSkNCmBgYA0KDQoNCmBgYHtyfQ0KIyBwYXJhbXNfdjYgPC0gc2V0UGFyYW1zKHBhcmFtc192NV90dW5lZCkNCg0Kc2ltX3Y2IDwtIHByb2plY3QocGFyYW1zX3Y1X3R1bmVkLCBlZmZvcnQ9MCwgdF9tYXggPSAyMDAwKQ0KDQpwbG90KHNpbV92NikNCnBsb3RseUJpb21hc3Moc2ltX3Y2KQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnBhcmFtc192NiA8LSBzdGVhZHkocGFyYW1zX3Y1X3R1bmVkKQ0KDQpwbG90QmlvbWFzc1ZzU3BlY2llcyhwYXJhbXNfdjYpDQpwbG90bHlTcGVjdHJhKHBhcmFtc192NiwgcG93ZXIgPSAyKQ0KDQpwYXJhbXNfdjYgPC0gY2FsaWJyYXRlQmlvbWFzcyhwYXJhbXNfdjYpDQpwbG90QmlvbWFzc1ZzU3BlY2llcyhwYXJhbXNfdjYpDQpgYGANCg0KYGBge3J9DQpwYXJhbXNfdjcgPC0gcGFyYW1zX3Y2IHw+DQogICAgbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8PiBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+DQogICAgbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8PiBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+DQogICAgbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8PiBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+DQogICAgbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8PiBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+DQogICAgbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8PiBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpDQpgYGANCmBgYHtyfQ0Kc2ltX3Y3IDwtIHByb2plY3QocGFyYW1zX3Y3LCBlZmZvcnQ9MCwgdF9tYXggPSAxMDAwKQ0KDQpwbG90KHNpbV92NykNCnBsb3RseUJpb21hc3Moc2ltX3Y3KQ0KbWl6ZXI6OnBsb3REaWV0KHBhcmFtc192NykNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc192OCA8LSB0dW5lR3Jvd3RoKHBhcmFtc192NykNCmBgYA0KDQoNCg0KYGBge3J9DQpwYXJhbXNfdjkgPC0gc3RlYWR5KHBhcmFtc192OCwgdF9tYXggPSAxMDAwKQ0KYGBgDQoNCg0KYGBge3J9DQpzaW1fdjggPC0gcHJvamVjdChwYXJhbXNfdjksIGVmZm9ydD0wLCB0X21heCA9IDEwMDApDQoNCnBsb3Qoc2ltX3Y4KQ0KcGxvdGx5QmlvbWFzcyhzaW1fdjgpDQpwYXJhbXNfdjlAc3BlY2llc19wYXJhbXMkZXJlcHJvDQpgYGANCg0KDQoNCg0KYGBge3J9DQpwYXJhbXNfdjlAc3BlY2llc19wYXJhbXMkZXJlcHJvDQoNCmNtIDwtIHBhcmFtc192OQ0KY20gPC0gc2V0QmV2ZXJ0b25Ib2x0KGNtLCBlcmVwcm8gPSBjKDAuMDA2NTM5MDg4LCAwLjAwODMyNDU4MCwgMC4wMTczNDE4OTYsIDAuMDExMTQ0MTg3LCAwLjAwMzkyNjE3NiwgMC4yMzU1NjA2ODYsIDAuMDEwNTA5NTUwLCAwLjA1MjM5MDA3MywgMC4yMDUyMzI1NDEsIDAuMiwgMC4yLCAwLjIsIDAuMiwgMC4yLCAwLjIpKQ0Kc3BlY2llc19wYXJhbXMoY20pIHw+IHNlbGVjdChlcmVwcm8sIFJfbWF4KQ0KDQpjbV92MSA8LSBzdGVhZHkoY20pDQpgYGANCg0KYGBge3J9DQpzaW1fY21fdjEgPC0gcHJvamVjdChjbV92MSwgZWZmb3J0PTAsIHRfbWF4ID0gMjAwMCkNCg0KcGxvdChzaW1fY21fdjEpDQpwbG90bHlCaW9tYXNzKHNpbV9jbV92MSkNCnBsb3RseVNwZWN0cmEoc2ltX2NtX3YxLCBwb3dlcj0xKQ0KYGBgDQoNCmBgYHtyfQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0Ka2FwcGEgPC0gIHJlc291cmNlX3BhcmFtcyhjbV92MSkka2FwcGENCmxhbWJkYSA8LSByZXNvdXJjZV9wYXJhbXMoY21fdjEpJGxhbWJkYQ0Kd19tYXggPC0gMTAwIA0Kd19mdWxsKGNtX3YxKVtbMV1dDQp3X21pbiA8LSAxZS0xMg0KYGBgDQoNCg0KDQoNCk5vdyB3ZSBwdXQgYWxsIHRoZXNlIHJlc291cmNlIHBhcmFtZXRlcnMgaW50byBhIGRhdGEgZnJhbWUuDQoNCmBgYHtyfQ0KU09fcmVzb3VyY2VfcGFyYW1zIDwtICBkYXRhLmZyYW1lKA0KICAgIHJlc291cmNlID0gYygicGwiKSwNCiAgICBsYW1iZGEgPSBjKGxhbWJkYSksDQogICAga2FwcGEgPSBjKGthcHBhKSwNCiAgICB3X21pbiA9IGMod19taW4pLA0KICAgIHdfbWF4ID0gYyh3X21heCkNCikNCg0KU09fcmVzb3VyY2VfcGFyYW1zDQpgYGANCg0KDQpgYGB7cn0NCnBhcmFtc19wbF9ycyA8LSBjbV92MQ0KcmVzb3VyY2VfcGFyYW1zKHBhcmFtc19wbF9ycykgPC0gU09fcmVzb3VyY2VfcGFyYW1zDQpgYGANCg0KDQpgYGB7cn0NCiMgcGFyYW1zX3BwYXJhbXNfcGxfcnNsX3JzIDwtIHNldFBhcmFtcyhwYXJhbXNfcGxfcnMpDQoNCnNpbV92X3BsX3JzIDwtIHByb2plY3QocGFyYW1zX3BsX3JzLCBlZmZvcnQ9MCwgdF9tYXggPSAxMDAwKQ0KDQpwbG90KHNpbV92X3BsX3JzKQ0KbWl6ZXI6OnBsb3REaWV0KHBhcmFtc19wbF9ycykNCmBgYA0KDQpgYGB7cn0NCm1pemVyOjpwbG90RGlldChwYXJhbXNfdjQpDQpgYGANCg0KDQpgYGB7cn0NCnBhcmFtcyA8LSByZWFkUkRTKCJ0dW5lZF9wYXJhbXMucmRzIikNCg0KcGFyYW1zIDwtIHN0ZWFkeShwYXJhbXMpDQoNCmBgYA0KDQpDaGVjayB0aGUgc3BlY3RyYQ0KYGBge3J9DQpwbG90bHlTcGVjdHJhKHBhcmFtcywgcG93ZXIgPSAyKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdEJpb21hc3NWc1NwZWNpZXMocGFyYW1zKQ0KYGBgDQpgYGB7cn0NCnBhcmFtcyA8LSBjYWxpYnJhdGVCaW9tYXNzKHBhcmFtcykNCnBsb3RCaW9tYXNzVnNTcGVjaWVzKHBhcmFtcykNCnBsb3RseVNwZWN0cmEocGFyYW1zKQ0KYGBgDQpSZXNjYWxlIHNwZWNpZXMgc3BlY3RyYQ0KYGBge3J9DQpwYXJhbXMgPC0gbWF0Y2hCaW9tYXNzZXMocGFyYW1zKQ0KcGxvdEJpb21hc3NWc1NwZWNpZXMocGFyYW1zKQ0KYGBgDQpDYW4gYWRkIHVwcGVyIGFuZCBsb3dlciBib3VuZGFyaWVzIGZvciBvYnNlcnZlZCBiaW9tYXNzIHJhbmdlDQpgYGB7cn0NCnBhcmFtc192MyA8LSB0dW5lUGFyYW1zKHBhcmFtcykNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdGx5U3BlY3RyYShwYXJhbXNfdjMpDQoNCnNpbSA8LSBwcm9qZWN0KHBhcmFtc192MywgZWZmb3J0ID0gMCAsIHRfbWF4ID0gNTAwKQ0KDQpwbG90KHNpbSkNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc192NCA8LSB0dW5lUGFyYW1zKHBhcmFtc192MykNCnBhcmFtc192NSA8LSB0dW5lR3Jvd3RoKHBhcmFtc192NCkNCnBhcmFtc192NiA8LSB0dW5lUGFyYW1zKHBhcmFtc192NSkNCg0KIyBzYXZlUkRTKHBhcmFtc192NiwgInBoYXNlMV9zdGVhZHkucmRzIikNCmBgYA0KDQpDaGVjayBtaXplckhvd1RvDQpDdXN0b21pc2UgdGhlIG1hdGNoIGJpb21hc3MgcGxvdHMgdG8gY29tcGFyZSB0aGUgY29ycmVjdCByYW5nZXMNCg0KYGBge3J9DQpwYXJhbXMgPC0gcmVhZFJEUygicGhhc2UxX3N0ZWFkeS5yZHMiKQ0KYGBgDQoNCkNoZWNrIGJpb21hc3MgaXMgYXQgc3RlYWR5LXN0YXRlDQpgYGB7cn0NCnNpbSA8LSBwcm9qZWN0KHBhcmFtcywgZWZmb3J0ID0gMCkNCg0KcGxvdGx5QmlvbWFzcyhzaW0pDQpwbG90bHlCaW9tYXNzT2JzZXJ2ZWRWc01vZGVsKHNpbSkNCmBgYA0KDQpDaGVjayBkaWV0cw0KYGBge3J9DQptaXplcjo6cGxvdERpZXQocGFyYW1zKQ0KYGBgDQp0cnkgdG8gcmVkdWNlIHRoZSBtYXhpbXVtIHNpemUgb2YgdGhlIGJhY2tncm91bmQgcmVzb3VyY2UgdG8gZm9yY2UgcHJlZGF0aW9uIGFtb25nIGR5bmFtaWNzIGdyb3Vwcw0KYGBge3J9DQpwYXJhbXNfd3BwX3YxIDwtIHNldFBhcmFtcyhwYXJhbXMsIHdfcHBfY3V0b2ZmID0gMTAwKQ0KDQpwYXJhbXNfd3BwX3YxIDwtIHNldFJlc291cmNlKHBhcmFtcywgd19wcF9jdXRvZmYgPSAxMDApDQpgYGANCg0KDQpgYGB7cn0NCnBhcmFtc193cHBfdjIgPC0gc3RlYWR5KHBhcmFtc193cHBfdjEpDQpgYGANCg0KYGBge3J9DQpwYXJhbXNfd3BwX3YzIDwtIHR1bmVQYXJhbXMocGFyYW1zX3dwcF92MikNCmBgYA0KDQoNCmBgYHtyfQ0Kc2ltX3YyIDwtIHByb2plY3QocGFyYW1zX3dwcF92MSwgdF9tYXggPSA1MDApDQpwbG90KHNpbV92MikNCmBgYA0KYGBge3J9DQptaXplcjo6cGxvdERpZXQocGFyYW1zX3dwcF92MSkNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX2d1ZXNzZWRfdjIgPC0gcGFyYW1zX2d1ZXNzZWQNCg0KcGFyYW1zX2d1ZXNzZWRfdjJAc3BlY2llc19wYXJhbXMkYmV0YVtwYXJhbXNfZ3Vlc3NlZF92MkBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJvcmNhIl0gIDwtIDEwMA0KYGBgDQoNClNvbWV0aGluZyBsaWtlICd5aWVsZENhdGNoJw0KDQpgYGB7cn0NCnBhcmFtc19ndWVzc2VkX3YyIDwtIHNldFBhcmFtcyhwYXJhbXNfZ3Vlc3NlZF92MikNCg0Kc2ltX3YyIDwtIHByb2plY3QocGFyYW1zX2d1ZXNzZWRfdjIsIGVmZm9ydD0wKQ0KDQpwbG90KHNpbV92MikNCnBsb3RseUZlZWRpbmdMZXZlbChzaW1fdjIpDQpwbG90bHlCaW9tYXNzKHNpbV92MikNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX3YzIDwtIHNldFBhcmFtcyhwYXJhbXNfZ3Vlc3NlZF92Miwgd19wcF9jdXRvZmYgPSAxMDAwMDApDQoNCnNpbV92MyA8LSBwcm9qZWN0KHBhcmFtc192MywgZWZmb3J0PTApDQoNCnBsb3Qoc2ltX3YzKQ0KcGxvdGx5RmVlZGluZ0xldmVsKHNpbV92MykNCnBsb3RseUJpb21hc3Moc2ltX3YzKQ0KYGBgDQoNCg0KYGBge3J9DQp0aGV0YV92MiA8LSB0aGV0YQ0KDQp0aGV0YV92Mls2LF0gIyBzbWFsbCBkaXZlcnMNCnRoZXRhX3YyWzksXSAjIGxlb3BhcmQgc2VhbHMNCnRoZXRhX3YyWzEzLF0gIyBvcmNhDQoNCnRoZXRhX3YyWzYsYygxOjQsNyw4KV0gPC0gMC41ICAjIHNtYWxsIGRpdmVycw0KdGhldGFfdjJbYygxOjQsNyw4KSwgNl0gPC0gMC41DQp0aGV0YV92Mls5LCBjKDE6NCw3LDgpXSA8LSAwLjUNCnRoZXRhX3YyW2MoMTo0LDcsOCksIDldIDwtIDAuNQ0KIyB0aGV0YV92MlsxMywgYygxOjQsNyw4KV0gDQojIHRoZXRhX3YyWzEzLCBjKDE6NCw3LDgpXQ0KDQp0aGV0YV92Mg0KYGBgDQoNCmBgYHtyfQ0KcGFyYW1zX3RoZXRhX3YyIDwtIG5ld011bHRpc3BlY2llc1BhcmFtcyhzcGVjaWVzX3BhcmFtcyA9IHNwZWNpZXNfcGFyYW1zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJhY3Rpb24gPSB0aGV0YV92MiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdfcHBfY3V0b2ZmID0gMTAwMDAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gMy80LCBwID0gMy80KQ0KDQpgYGANCg0KYGBge3J9DQpib3gucGFyYW1zX3YyIDwtIHBhcmFtc190aGV0YV92Mg0KDQpib3gucGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHBwbXJfbWluW2JveC5wYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAiYmFsZWVuIHdoYWxlcyJdICA8LSAxZTUNCmJveC5wYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkcHBtcl9tYXhbYm94LnBhcmFtc192MkBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJiYWxlZW4gd2hhbGVzIl0gPC01ZTcNCmJveC5wYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkcHJlZF9rZXJuZWxfdHlwZVtib3gucGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gImJhbGVlbiB3aGFsZXMiXSA8LSAiYm94Ig0KYGBgDQoNCg0KYGBge3J9DQpwYXJhbXNfdjIgPC0gYm94LnBhcmFtc192Mg0KDQpwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkUl9tYXggPC1wYXJhbXNfdjJAcmVzb3VyY2VfcGFyYW1zJGthcHBhKnBhcmFtc192MkBzcGVjaWVzX3BhcmFtcyR3X2luZl4tMS41DQoNCnBhcmFtc192MiA8LSBzZXRQYXJhbXMocGFyYW1zX3YyKQ0KDQpzaW1fdjIgPC0gcHJvamVjdChwYXJhbXNfdjIsIGVmZm9ydD0wKQ0KDQpwbG90KHNpbV92MikNCnBsb3RseUZlZWRpbmdMZXZlbChzaW1fdjIpDQpwbG90bHlCaW9tYXNzKHNpbV92MikNCiMgcGxvdERpZXQoc2ltX3YyKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdFNwZWN0cmEoc2ltX3YyLCBwb3dlciA9IDIpDQpgYGANCg0KDQpgYGB7cn0NCnBhcmFtc190dW5lZF92MSA8LSB0dW5lR3Jvd3RoKHBhcmFtc19ndWVzc2VkKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmxpYnJhcnkobWl6ZXJNUikNCnJlc291cmNlX2ludGVyYWN0aW9uKHBhcmFtc19ndWVzc2VkKQ0KI3NldCB2ZWN0b3JzIG9mIHBsYW5rdG9uIGFuZCBiZW50aG9zIGF2YWlsYWJpbGl0eSBmb3IgdGhlIG1vZGVsIHNwZWNpZXMgDQpwbGFua3Rvbl9hdmFpbCA8LSBjKDEsIDAuOCwgMC41LCAwLjUsIDAuNSwgMC41LCAwLjUsIDAuNSwgMC41LCAwLjUpDQojIGJlbnRob3NfYXZhaWwgPC0gYygwLjIsIDEsIDEsIDEsIDEsIDEsIDAuNSwgMC41LCAwLjUsIDAuNSkNCg0KI3B1dCB0aGVtIGludG8gY29ycmVzcG9uZGluZyBjb2x1bW5zIG9mIHJlc291cmNlX2ludGVyYWN0aW9uIG1hdHJpeA0KcmVzb3VyY2VfaW50ZXJhY3Rpb24oc2ltX2d1ZXNzZWQpWywgMV0gPC0gcGxhbmt0b25fYXZhaWwNCnJlc291cmNlX2ludGVyYWN0aW9uKGN1cl9tb2RlbClbLCAyXSA8LSBiZW50aG9zX2F2YWlsDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyBwbG90QmlvbWFzc1ZzU3BlY2llcyhwYXJhbXNfZ3Vlc3NlZCkNCg0KIyBwYXJhbXNfdjAgPC0gY2FsaWJyYXRlQmlvbWFzcyhwYXJhbXNfZ3Vlc3NlZCkNCiMgcGFyYW1zX3YwIDwtIG1hdGNoQmlvbWFzc2VzKHBhcmFtc19ndWVzc2VkKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyByZXNvdXJjZV9wYXJhbXMocGFyYW1zX2d1ZXNzZWQpDQpgYGANCg0KYGBge3J9DQojIGthcHBhIDwtICByZXNvdXJjZV9wYXJhbXMocGFyYW1zX2d1ZXNzZWQpJGthcHBhDQojIGxhbWJkYSA8LSByZXNvdXJjZV9wYXJhbXMocGFyYW1zX2d1ZXNzZWQpJGxhbWJkYQ0KIyANCiMgd19tYXggPC0gMTANCiMgDQojIHdfZnVsbChwYXJhbXNfZ3Vlc3NlZClbWzFdXQ0KYGBgDQoNCmBgYHtyfQ0KIyB3X21pbiA8LSAxZS0xMg0KYGBgDQoNCg0KDQoNClNldHVwIGFwZXggcHJlZGF0b3IgcmVzb3VyY2UNCmBgYHtyfQ0KIyAjIFNldCBhcF9yc3Mga2FwcGEgc2FtZSBhcyBwbGFua3RvbiBrYXBwYSANCiMga2FwcGFfYXAgPC0ga2FwcGENCiMgDQojICMgQXNzdW1lIG1vcmUgc2hhbGxvdyBzbG9wZSBmb3IgYmVudGhvcyANCiMgbGFtYmRhX2FwIDwtIGxhbWJkYQ0KIyAjIFNldCBtYXhpbXVtIGFwIHByZXkgc2l6ZQ0KIyB3X21heF9hcCA8LSAxMDAwMDAwMA0KIyAjIFNldCBtaW5pbXVtIGFwIHByZXkgc2l6ZQ0KIyB3X21pbl9hcCA8LSAxMDAwDQpgYGANCg0KDQpgYGB7cn0NCiMgIyBTZXQgYmVudGhvcyBrYXBwYSBzYW1lIGFzIHBsYW5rdG9uIGthcHBhIA0KIyBrYXBwYV9iZW4gPC0ga2FwcGENCiMgIyBBc3N1bWUgbW9yZSBzaGFsbG93IHNsb3BlIGZvciBiZW50aG9zIA0KIyBsYW1iZGFfYmVuIDwtIDEuOQ0KIyAjIFNldCBtYXhpbXVtIGJlbnRob3Mgc2l6ZSANCiMgd19tYXhfYmVuIDwtIDEwDQojICMgQmVudGhvcyBzdGFydHMgYXQgbGFyZ2VyIHNpemVzLCBjb3JyZXNwb25kaW5nIHRvIGFib3V0IDEtMm1tDQojIHdfbWluX2JlbiA8LSAwLjAwMDENCmBgYA0KDQoNCg0KTm93IHdlIHB1dCBhbGwgdGhlc2UgcmVzb3VyY2UgcGFyYW1ldGVycyBpbnRvIGEgZGF0YSBmcmFtZS4NCg0KYGBge3J9DQojIE1GU09fcmVzb3VyY2VfcGFyYW1zIDwtIGRhdGEuZnJhbWUoDQojICAgICByZXNvdXJjZSA9IGMoInBsIiwgImFwIiksDQojICAgICBsYW1iZGEgPSBjKGxhbWJkYSwgbGFtYmRhX2FwKSwNCiMgICAgIGthcHBhID0gYyhrYXBwYSwgIGthcHBhX2FwKSwNCiMgICAgIHdfbWluID0gYyh3X21pbiwgd19taW5fYXApLA0KIyAgICAgd19tYXggPSBjKHdfbWF4LCAgd19tYXhfYXApDQojICkNCiMgDQojIE1GU09fcmVzb3VyY2VfcGFyYW1zDQpgYGANCg0KV2UgY2FuIG5vdyB1cGRhdGUgb3VyIG1vZGVsIHRvIHVzZSB0aGVzZSByZXNvdXJjZSBwYXJhbWV0ZXJzIHdpdGgNCg0KYGBge3J9DQojIHJlc291cmNlX3BhcmFtcyhwYXJhbXNfZ3Vlc3NlZCkgPC0gTUZTT19yZXNvdXJjZV9wYXJhbXMNCmBgYA0KDQoNCmBgYHtyfQ0KIyByZXNvdXJjZV9pbnRlcmFjdGlvbihwYXJhbXNfZ3Vlc3NlZCkNCmBgYA0KDQoNCg0KYGBge3J9DQojICNzZXQgdmVjdG9ycyBvZiBwbGFua3RvbiBhbmQgYmVudGhvcyBhdmFpbGFiaWxpdHkgZm9yIHRoZSBtb2RlbCBzcGVjaWVzIA0KIyBwbGFua3Rvbl9hdmFpbCA8LSBjKDEsIDEsIDEsIDEsIDEsIDEsIDEsIDEsIDEsIDAuNSwgMC41LCAwLjI1KQ0KIyBhcF9hdmFpbCA8LSBjKDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAuMjUsIDAuNzUsIDAuNzUsIDApDQojIA0KIyAjcHV0IHRoZW0gaW50byBjb3JyZXNwb25kaW5nIGNvbHVtbnMgb2YgcmVzb3VyY2VfaW50ZXJhY3Rpb24gbWF0cml4DQojIHJlc291cmNlX2ludGVyYWN0aW9uKHBhcmFtc19ndWVzc2VkKVssIDFdIDwtIHBsYW5rdG9uX2F2YWlsDQojIHJlc291cmNlX2ludGVyYWN0aW9uKHBhcmFtc19ndWVzc2VkKVssIDJdIDwtIGFwX2F2YWlsDQpgYGANCg0KQ29uZmlybSBpdCB3b3JrZWQNCmBgYHtyfQ0KIyByZXNvdXJjZV9pbnRlcmFjdGlvbihwYXJhbXNfZ3Vlc3NlZCkNCmBgYA0KDQpUcnkgYHN0ZWFkeWAgZm9yIGEgbGF1Z2gNCmBgYHtyfQ0KTUZTT19tb2QgPC0gc3RlYWR5KHBhcmFtc19ndWVzc2VkKQ0KYGBgDQoNCk5haCwgZGlkbid0IHRoaW5rIHNvLi4uaGFuZyBvbiBhIHNlY29uZCEgDQoNCmBgYHtyfQ0KcGxvdGx5U3BlY3RyYShNRlNPX21vZCwgcG93ZXIgPSAyKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdEJpb21hc3NWc1NwZWNpZXMoTUZTT19tb2QpDQpgYGANCg0KYGBge3J9DQpNRlNPX21vZCA8LSBjYWxpYnJhdGVCaW9tYXNzKE1GU09fbW9kKQ0KcGxvdEJpb21hc3NWc1NwZWNpZXMoTUZTT19tb2QpDQpgYGANCg0KYGBge3J9DQpNRlNPX21vZCA8LSBtYXRjaEJpb21hc3NlcyhNRlNPX21vZCkNCnBsb3RCaW9tYXNzVnNTcGVjaWVzKE1GU09fbW9kKQ0KYGBgDQoNCmBgYHtyfQ0KTUZTT19tb2QgPC0gc3RlYWR5KE1GU09fbW9kKQ0KYGBgDQoNCmBgYHtyfQ0KTUZTT19tb2QgPC0gc3RlYWR5KE1GU09fbW9kKQ0KcGxvdEJpb21hc3NWc1NwZWNpZXMoTUZTT19tb2QpDQpgYGANCg0KYGBge3J9DQpNRlNPX21vZCA8LSBNRlNPX21vZCB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKQ0KYGBgDQoNCkluY3JlYXNlIGthcHBhIHRvIGhlbHAgZXJlcHJvIHZhbHVlcyB0aGF0IGFyZSB0b28gbGFyZ2UuDQpuZXdNdWx0aXNwZWNpZXMgdG8gYWRqdXN0IGthcHBhLCBvciBpbiB0dW5lUGFyYW1zKCksIGJ1dCB5b3UgbmVlZCB0byBtYWtlIHN1cmUgdGhhdCBrYXBwYSBpcyBhY3R1YWxseSBjaGFuZ2luZy4NCg0KYGBge3J9DQpwbG90QmlvbWFzc1ZzU3BlY2llcyhNRlNPX21vZCkNCnBsb3RTcGVjdHJhKE1GU09fbW9kLCBwb3dlciA9IDIpDQpgYGANCg0KDQpgYGB7cn0NCnBhcmFtc192MiA8LSBNRlNPX21vZA0KDQojIHdyaXRlX3JkcyhwYXJhbXNfdjIsICJ0dW5lZF9wYXJhbXMuUkRTIikNCg0KcGFyYW1zX3YyIDwtIHNldFBhcmFtcyhwYXJhbXNfdjIpDQoNCnNpbV92MiA8LSBwcm9qZWN0KHBhcmFtc192MiwgZWZmb3J0PTApDQoNCnBsb3Qoc2ltX3YyKQ0KcGxvdGx5U3BlY3RyYShzaW1fdjIpDQojIHBsb3REaWV0KHNpbV92MikNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1fc2V0dXAgPC0gcGFyYW1zX3YyDQpwYXJhbV9zZXR1cEByZXNvdXJjZV9wYXJhbXMka2FwcGENCg0KcGFyYW1fc2V0dXBAc3BlY2llc19wYXJhbXMkUl9tYXhbXQ0KcGFyYW1fc2V0dXBAc3BlY2llc19wYXJhbXMkZXJlcHJvW10NCmBgYA0KDQpgYGB7cn0NCnBhcmFtc19yZWRfcHBfdjEgPC0gcGFyYW1fc2V0dXANCg0Kc3RyKHJlc291cmNlX3BhcmFtcyhwYXJhbXNfcmVkX3BwX3YxKSkNCiMgbWl6ZXI6OnJlc291cmNlX3BhcmFtcyhwYXJhbXNfcmVkX3BwX3YxKSR3X3BwX2N1dG9mZiA8LSAxMA0KDQptaXplcjo6cmVzb3VyY2VfcGFyYW1zKHBhcmFtcylbWyJ3X3BwX2N1dG9mZiJdXSA8LSAxMA0KDQpgYGANCg0KYGBge3J9DQpwYXJhbXNfcmVkX3BwX3YxIDwtIHN0ZWFkeShwYXJhbXNfcmVkX3BwX3YxKQ0KYGBgDQoNCmBgYHtyfQ0KTUZTT19tb2QgPC0gbWF0Y2hCaW9tYXNzZXMocGFyYW1zX3JlZF9wcF92MSkNCnBsb3RCaW9tYXNzVnNTcGVjaWVzKHBhcmFtc19yZWRfcHBfdjEpDQptaXplck1SOjpwbG90bHlTcGVjdHJhKHBhcmFtX3NldHVwKQ0KbWl6ZXJNUjo6cGxvdGx5U3BlY3RyYShwYXJhbXNfcmVkX3BwX3YxKQ0KbWl6ZXJNUjo6cGxvdERpZXQocGFyYW1zX3JlZF9wcF92MSkNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX3JlZF9wcF92MiA8LSBzZXRQYXJhbXMocGFyYW1zX3JlZF9wcF92MSwgd19wcF9jdXRvZmYgPSAxMDAwMCkNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc19yZWRfcHBfdjIgPC0gc3RlYWR5KHBhcmFtc19yZWRfcHBfdjIpDQpgYGANCg0KDQpgYGB7cn0NCk1GU09fbW9kX3YyIDwtIG1hdGNoQmlvbWFzc2VzKHBhcmFtc19yZWRfcHBfdjIpDQpwbG90QmlvbWFzc1ZzU3BlY2llcyhwYXJhbXNfcmVkX3BwX3YyKQ0KbWl6ZXJNUjo6cGxvdGx5U3BlY3RyYShwYXJhbXNfcmVkX3BwX3YxKQ0KbWl6ZXJNUjo6cGxvdGx5U3BlY3RyYShwYXJhbXNfcmVkX3BwX3YyKQ0KcGxvdEZlZWRpbmdMZXZlbChwYXJhbXNfcmVkX3BwX3YyLCBpbmNsdWRlX2NyaXRpY2FsID0gVCkNCm1pemVyTVI6OnBsb3REaWV0KHBhcmFtc19yZWRfcHBfdjIpDQpgYGANCg0KYGBge3J9DQpwYXJhbXNfcmVkX3BwX3YzIDwtIHNldFBhcmFtcyhwYXJhbXNfcmVkX3BwX3YyLCB3X3BwX2N1dG9mZiA9IDEwMDApDQpgYGANCg0KYGBge3J9DQpwYXJhbXNfcmVkX3BwX3YzIDwtIHN0ZWFkeShwYXJhbXNfcmVkX3BwX3YzKQ0KYGBgDQoNCmBgYHtyfQ0KTUZTT19tb2RfdjMgPC0gbWF0Y2hCaW9tYXNzZXMocGFyYW1zX3JlZF9wcF92MykNCnBsb3RCaW9tYXNzVnNTcGVjaWVzKHBhcmFtc19yZWRfcHBfdjMpDQptaXplck1SOjpwbG90bHlTcGVjdHJhKHBhcmFtc19yZWRfcHBfdjIpDQptaXplck1SOjpwbG90bHlTcGVjdHJhKHBhcmFtc19yZWRfcHBfdjMpDQpwbG90RmVlZGluZ0xldmVsKHBhcmFtc19yZWRfcHBfdjMsIGluY2x1ZGVfY3JpdGljYWwgPSBUKQ0KbWl6ZXJNUjo6cGxvdERpZXQocGFyYW1zX3JlZF9wcF92MykNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX3JlZF9wcF92NCA8LSBzZXRQYXJhbXMocGFyYW1zX3JlZF9wcF92Mywgd19wcF9jdXRvZmYgPSAxMDApDQpgYGANCg0KYGBge3J9DQpwYXJhbXNfcmVkX3BwX3Y0IDwtIHN0ZWFkeShwYXJhbXNfcmVkX3BwX3Y0KQ0KYGBgDQoNCmBgYHtyfQ0KTUZTT19tb2RfdjQgPC0gbWF0Y2hCaW9tYXNzZXMocGFyYW1zX3JlZF9wcF92NCkNCnBsb3RCaW9tYXNzVnNTcGVjaWVzKHBhcmFtc19yZWRfcHBfdjQpDQptaXplck1SOjpwbG90bHlTcGVjdHJhKHBhcmFtc19yZWRfcHBfdjMpDQptaXplck1SOjpwbG90bHlTcGVjdHJhKHBhcmFtc19yZWRfcHBfdjQpDQpwbG90RmVlZGluZ0xldmVsKHBhcmFtc19yZWRfcHBfdjQsIGluY2x1ZGVfY3JpdGljYWwgPSBUKQ0KbWl6ZXJNUjo6cGxvdERpZXQocGFyYW1zX3JlZF9wcF92NCkNCmBgYA0KDQpgYGB7cn0NCnBhcl90ZXN0IDwtIHBhcmFtX3NldHVwDQojIHBhcl90ZXN0QHJlc291cmNlX3BhcmFtcyRrYXBwYSA8LSAxOC4zNTkzDQoNCiMgbmV3X3ZhcnkgPC0gYyhwYXJhbV9zZXR1cEBzcGVjaWVzX3BhcmFtcyRSX21heCwgMTguMzU5MykNClJtYXhfdmFyeSA8LSBjKHBhcl90ZXN0QHNwZWNpZXNfcGFyYW1zJFJfbWF4KQ0KZXJlcHJvX3ZhcnkgPC0gYyhwYXJfdGVzdEBzcGVjaWVzX3BhcmFtcyRlcmVwcm8pDQpiaW9fdmFyeSA8LSBjKHBhcl90ZXN0QHNwZWNpZXNfcGFyYW1zJFJfbWF4LCBwYXJfdGVzdEByZXNvdXJjZV9wYXJhbXMka2FwcGEpDQoNCg0KZ2V0RXJyb3JfUm1heCh2YXJ5ID0gUm1heF92YXJ5LCBwYXJhbXMgPSBwYXJfdGVzdCwgZGF0ID0gcGFyX3Rlc3RAc3BlY2llc19wYXJhbXMkYmlvbWFzc19vYnNlcnZlZCwgZGF0YV90eXBlPSJiaW9tYXNzIiwgdGltZXRvcnVuID0gMTAwKQ0KDQpnZXRFcnJvcl9lcmVwcm8odmFyeSA9IGVyZXByb192YXJ5LCBwYXJhbXMgPSBwYXJfdGVzdCwgZGF0ID0gcGFyX3Rlc3RAc3BlY2llc19wYXJhbXMkYmlvbWFzc19vYnNlcnZlZCwgZGF0YV90eXBlPSJiaW9tYXNzIiwgdGltZXRvcnVuID0gMTAwKQ0KDQpnZXRFcnJvcl9CaW8odmFyeSA9IGJpb192YXJ5LCBwYXJhbXMgPSBwYXJfdGVzdCwgZGF0ID0gcGFyX3Rlc3RAc3BlY2llc19wYXJhbXMkYmlvbWFzc19vYnNlcnZlZCwgZGF0YV90eXBlPSJiaW9tYXNzIiwgdGltZXRvcnVuID0gMTAwKQ0KYGBgDQoNCmBgYHtyfQ0KbWluKHBhcmFtX3NldHVwQHNwZWNpZXNfcGFyYW1zJFJfbWF4W10pDQptYXgocGFyYW1fc2V0dXBAc3BlY2llc19wYXJhbXMkUl9tYXhbXSkNCmBgYA0KDQoNCk9wdGltaXNlDQoNCmBgYHtyfQ0KbGlicmFyeShwYXJhbGxlbCkNCiNjcmVhdGUgYSBzZXQgb2YgcGFyYW1zIGZvciB0aGUgb3B0aW1pc2F0aW9uIHByb2Nlc3MNCnBhcmFtc19vcHRpbSA8LSBwYXJfdGVzdA0KcGFyYW1zX29wdGltIDwtIHNldFBhcmFtcyhwYXJhbXNfb3B0aW0pDQoNCiNzZXQgdXAgd29ya2Vycw0Kbm9Db3JlcyA8LSBkZXRlY3RDb3JlcygpIC0gMiAjIGtlZXAgc29tZSBzcGFyZSBjb3Jlcw0KY2wgPC0gbWFrZUNsdXN0ZXIobm9Db3Jlcywgc2V0dXBfdGltZW91dCA9IDAuNSkNCnNldERlZmF1bHRDbHVzdGVyKGNsID0gY2wpDQpjbHVzdGVyRXhwb3J0KGNsLCBhcy5saXN0KGxzKCkpKQ0KY2x1c3RlckV2YWxRKGNsLCB7DQogIGxpYnJhcnkobWl6ZXJFeHBlcmltZW50YWwpDQogIGxpYnJhcnkobWl6ZXJNUikNCiAgbGlicmFyeShvcHRpbVBhcmFsbGVsKQ0KfSkNCg0Kb3B0aW1fcmVzdWx0IDwtIG9wdGltUGFyYWxsZWw6Om9wdGltUGFyYWxsZWwocGFyPVJtYXhfdmFyeSxnZXRFcnJvcl9SbWF4LHBhcmFtcz1wYXJhbXNfb3B0aW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0ID0gcGFyYW1zQHNwZWNpZXNfcGFyYW1zJGJpb21hc3Nfb2JzZXJ2ZWQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YV90eXBlPSJiaW9tYXNzIiwgdGltZXRvcnVuID0gMTAwLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9IkwtQkZHUy1CIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyPWMocmVwKDFlLTIwLGxlbmd0aChwYXJhbXNAc3BlY2llc19wYXJhbXMkc3BlY2llcykpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyPSBjKHJlcCgxMCxsZW5ndGgocGFyYW1zQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMpKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1saXN0KGxvZ2luZm89VFJVRSwgZm9yd2FyZD1UUlVFKSkNCnN0b3BDbHVzdGVyKGNsKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc19vcHRpbUBzcGVjaWVzX3BhcmFtcyRSX21heA0KIyBwYXJhbXNfb3B0aW1Ac3BlY2llc19wYXJhbXMkZXJlcHJvDQoNCg0Kb3B0aW1fcmVzdWx0JHBhclsxOjEyXQ0KIyBvcHRpbV9yZXN1bHQkcGFyWzEzXQ0KYGBgDQoNCmBgYHtyfQ0KcGFyYW1zX29wdGltX3YyIDwtIHBhcmFtc19vcHRpbQ0KIyBub3cgcHV0IHRoZXNlIG5ldyBSbWF4cw0KIyBvcHRpbSB2YWx1ZXM6DQogcGFyYW1zX29wdGltX3YyQHNwZWNpZXNfcGFyYW1zJFJfbWF4IDwtIG9wdGltX3Jlc3VsdCRwYXJbMToxMl0gIyByZW1vdmVkIHRoZSAxMF4NCiAjIHBhcmFtc19vcHRpbUBzcGVjaWVzX3BhcmFtcyRlcmVwcm8gPC0gb3B0aW1fcmVzdWx0JHBhclsxOjEyXQ0KDQogIyBwYXJhbXNfb3B0aW1AcmVzb3VyY2VfcGFyYW1zJGthcHBhIDwtIG9wdGltX3Jlc3VsdCRwYXJbMTNdDQogDQogIyB2YXJ5X29wdGltIDwtIG9wdGltX3Jlc3VsdCRwYXINCiAjIHZhcnlfb3B0aW1bMTNdIDwtIDFlMw0KICMgDQogIyBnZXRFcnJvckJpbzIodmFyeSA9IHZhcnlfb3B0aW0sDQogIyAgICAgICAgICAgICAgcGFyYW1zX29wdGltLCBkYXQgPSBwYXJhbXNfb3B0aW1Ac3BlY2llc19wYXJhbXMkYmlvbWFzc19vYnNlcnZlZCkNCiANCiAjY2hlY2sgdmFsdWVzIF5eIGhhdmUgdGhleSBnb25lIHRvIG1heC9taW4gZXRjLg0KIA0KcGFyYW1zX29wdGltX3YyQHNwZWNpZXNfcGFyYW1zJG1heF9saW0gPC0gMTANCnBhcmFtc19vcHRpbV92MkBzcGVjaWVzX3BhcmFtcyRtaW5fbGltIDwtIDFlLTIwDQojIA0KcGFyYW1zX29wdGltX3YyQHNwZWNpZXNfcGFyYW1zJFJfbWF4ID4gcGFyYW1zX29wdGltX3YyQHNwZWNpZXNfcGFyYW1zJG1pbl9saW0NCnBhcmFtc19vcHRpbV92MkBzcGVjaWVzX3BhcmFtcyRSX21heCA8IHBhcmFtc19vcHRpbV92MkBzcGVjaWVzX3BhcmFtcyRtYXhfbGltDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIHBhcmFtc19vcHRpbV92MiA8LXNldFBhcmFtcyhwYXJhbXNfb3B0aW1fdjIpDQogc2ltX29wdGltIDwtIHByb2plY3QocGFyYW1zX29wdGltX3YyLCBlZmZvcnQgPTAsIHRfbWF4ID0gMTAwKQ0KDQogcGxvdChzaW1fb3B0aW0pDQogcGxvdGx5QmlvbWFzcyhzaW1fb3B0aW0pDQogcGxvdERpZXQoc2ltX29wdGltKQ0KYGBgDQoNCk9wdGltaXNlIGFnYWluDQoNCmBgYHtyfQ0KcGFyYW1zX29wdGltX3YyQHJlc291cmNlX3BhcmFtcyRrYXBwYSANCmBgYA0KDQpgYGB7cn0NCnBhcmFtc19vcHRpbV92MyA8LSBzdGVhZHkocGFyYW1zX29wdGltX3YyKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdFNwZWN0cmEocGFyYW1zX29wdGltX3YzLCBwb3dlciA9MikNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc19vcHRpbV92NCA8LSB0dW5lR3Jvd3RoKHBhcmFtc19vcHRpbV92MykNCnBhcmFtc19vcHRpbV92NCA8LSBzdGVhZHkocGFyYW1zX29wdGltX3Y0KQ0KYGBgDQoNCmBgYHtyfQ0KcGFyYW1zX29wdGltX3Y0IDwtIHJlYWRSRFMoInBhcmFtc19vcHRpbV92NC5SRFMiKQ0KDQpzaW1fdjMgPC0gcHJvamVjdChwYXJhbXNfb3B0aW1fdjQsIGVmZm9ydCA9MCwgdF9tYXggPSAxMDApDQpwbG90QmlvbWFzc1ZzU3BlY2llcyhwYXJhbXNfb3B0aW1fdjQpDQpwbG90RGlldChwYXJhbXNfb3B0aW1fdjQpDQpwbG90QmlvbWFzcyhzaW1fdjMpDQpwbG90bHlTcGVjdHJhKHNpbV92MykNCnAxIDwtIHBsb3RTcGVjdHJhKHNpbV92MykNCg0KIyBzYXZlUkRTKHBhcmFtc19vcHRpbV92NCwgInBhcmFtc19vcHRpbV92NC5SRFMiKQ0KdGlmZihmaWxlPSJzYXZpbmdfc3BlY3RyYV9wbG90LnRpZmYiLA0Kd2lkdGg9NiwgaGVpZ2h0PTQsIHVuaXRzPSJpbiIsIHJlcz01MDApDQpwMQ0KZGV2Lm9mZigpDQoNCmBgYA0KSWYNCkFBRCByZWNvbW1lbmQgdGhhdCBiZW50aGljIHJlc291cmNlIGlzIG5vdCBtZWFuaW5nZnVsIGZvciB0b290aGZpc2gNCg0KUm1heCBjYW4gYmUganVzdGlmaWVkIGJ5IGFwcGx5aW5nIGEgZGVuc2l0eSBkZXBlbmRlbmNlIHJlbGF0aW9uc2hpcCBhY2NvcmRpbmcgdG8gdGhlIHRyYWl0IGJhc2VkIG1vZGVsIChBbmRlcnNvbikNCklmIGZpbmlzaGVkIHdpdGggYW4gb3B0aW0gcnVuLCBjb3VsZCByZS1pbnRyb2R1Y2UgZGVuc2l0eSBkZXBlbmRlbmNlIHRoYXQgaGFzIGJlZW4gb3ZlciB3cml0dGVuIGJ5IHN0ZWFkeSgpDQoNCldlIGRvbid0IGtub3cgd2hhdCB0aGUgbGV2ZWwgb2YgZGVuc2l0eSBkZXBlbmRlbmNlIHNob3VsZCBiZSBzZXQgYXQuIENhbiB1c2UgeWllbGQgY3VydmVzLCBzZW5zaXRpdml0eSB0byBtb3J0YWxpdHkuLi5oYXJ2ZXN0aW5nIA0KDQpQcmlzdGluZSB3aGFsZSBiaW9tYXNzIHByZS13aGFsaW5nLiBUaGUgJ2Jhc2UnIG1vZGVsIGlzIGFjdHVhbGx5IHRoZSBoaWdobHkgZXhwbG9pdGVkIHN5c3RlbSwgY2FuIGNvbXBhcmUgaGlzdG9yaWNhbCB3aGFsaW5nIHRpbWUgc2VyaWVzIChDaHJpcyBDbGVtZW50cyBhbmQgSnVsaWEgaGF2ZSB0aGlzIGRhdGEpDQoNCkJvZHkgc2l6ZSBvZiB3aGFsZXMgcmVzcG9uZGluZyB0byBmaXNoaW5nIA0KLSBGb2xsb3cgDQoNCkVtcHJpY2lhbCBzaXplIGRpc3RyaWJzIG9mIG1hbW1hbHMNCg0KeWllbGQNCg0Kc2VhYXJvdW5kdXMNCg0KV2UgYXJlIGNvbnNpZGVyaW5nIHRoZSB3aGFsZXMgd2l0aGluIHRoZSBQcnlkeiBCYXkNCg0KR2VhciBhbmQgY2F0Y2ggYWJpbGl0eSBmb3Iga3JpbGwsIGljZSBmaXNoIGFuZCB0b290aGZpc2gNCg0KQ29tYmluZSBTdGFjZXkvUm9zaG5pIG1vZGVsIGFuZCBnZXQgYSB0b3RhbCBiaW9tYXNzDQoNCg0KYGBge3J9DQpwYXJhbXNfb3B0aW1fdjRAc3BlY2llc19wYXJhbXMkZXJlcHJvDQpwYXJhbXNfb3B0aW1fdjUgPC0gdHVuZVBhcmFtcyhwYXJhbXNfb3B0aW1fdjQpDQojIHBhcmFtc19vcHRpbV92NSA8LSB0dW5lR3Jvd3RoKHBhcmFtc19vcHRpbV92NCkNCg0KZ2V0UmVwcm9kdWN0aW9uTGV2ZWwocGFyYW1zX29wdGltX3Y0KSAjIG5vIGRlbnNpdHkgZGVwZW5kZW5jZSBmb3IgZ3JvdXBzIHdpdGggMA0KDQojIENhbiB0cnkgb3B0aW1pc2Ugd2l0aCByZXByb2R1Y3Rpb24gbGV2ZWwNCg0KcGFyYW1zX29wdGltX3Y0QHNwZWNpZXNfcGFyYW1zJFJfbWF4DQpwYXJhbXNfb3B0aW1fdjRAc3BlY2llc19wYXJhbXMkZXJlcHJvDQoNCg0KYGBgDQpGaXJzdCBlY29zeXN0ZW0gbWl6ZXIgbW9kZWwNCg0KYGBge3J9DQojIGxpYnJhcnkocGFyYWxsZWwpDQojICNjcmVhdGUgYSBzZXQgb2YgcGFyYW1zIGZvciB0aGUgb3B0aW1pc2F0aW9uIHByb2Nlc3MNCiMgIyBwYXJhbV9vcHRpbV92Mg0KIyBwYXJhbV9vcHRpbV92MiA8LSBzZXRQYXJhbXMocGFyYW1fb3B0aW1fdjIpDQojIA0KIyAjc2V0IHVwIHdvcmtlcnMNCiMgbm9Db3JlcyA8LSBkZXRlY3RDb3JlcygpIC0gMiAjIGtlZXAgc29tZSBzcGFyZSBjb3Jlcw0KIyBjbCA8LSBtYWtlQ2x1c3Rlcihub0NvcmVzLCBzZXR1cF90aW1lb3V0ID0gMC41KQ0KIyBzZXREZWZhdWx0Q2x1c3RlcihjbCA9IGNsKQ0KIyBjbHVzdGVyRXhwb3J0KGNsLCBhcy5saXN0KGxzKCkpKQ0KIyBjbHVzdGVyRXZhbFEoY2wsIHsNCiMgICBsaWJyYXJ5KG1pemVyRXhwZXJpbWVudGFsKQ0KIyAgIGxpYnJhcnkobWl6ZXJNUikNCiMgICBsaWJyYXJ5KG9wdGltUGFyYWxsZWwpDQojIH0pDQojIA0KIyBvcHRpbV9yZXN1bHQgPC0gb3B0aW1QYXJhbGxlbDo6b3B0aW1QYXJhbGxlbChwYXI9YmlvX3ZhcnksZ2V0RXJyb3JfQmlvLHBhcmFtcz1wYXJhbXNfb3B0aW0sIA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXQgPSBwYXJhbXNAc3BlY2llc19wYXJhbXMkYmlvbWFzc19vYnNlcnZlZCwgDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFfdHlwZT0iYmlvbWFzcyIsIHRpbWV0b3J1biA9IDEwMCwgDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9IkwtQkZHUy1CIiwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXI9YyhyZXAoMWUtMjAsbGVuZ3RoKHBhcmFtc0BzcGVjaWVzX3BhcmFtcyRzcGVjaWVzKSksMSksDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyPSBjKHJlcCgxMCxsZW5ndGgocGFyYW1zQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMpKSwxZSsxNSksDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPWxpc3QobG9naW5mbz1UUlVFLCBmb3J3YXJkPVRSVUUpKQ0KIyBzdG9wQ2x1c3RlcihjbCkNCmBgYA0KDQoNCiMjIEFkZCBCZW50aGljIFJlc291cmNlIFNwZWN0cnVtDQoNCmBgYHtyfQ0KIyBTZXQgYmVudGhvcyBrYXBwYSBzYW1lIGFzIHBsYW5rdG9uIGthcHBhDQprYXBwYV9iZW4gPC0ga2FwcGENCiMgQXNzdW1lIG1vcmUgc2hhbGxvdyBzbG9wZSBmb3IgYmVudGhvcw0KbGFtYmRhX2JlbiA8LSAxLjkNCiMgU2V0IG1heGltdW0gYmVudGhvcyBzaXplDQp3X21heF9iZW4gPC0gMTANCiMgQmVudGhvcyBzdGFydHMgYXQgbGFyZ2VyIHNpemVzLCBjb3JyZXNwb25kaW5nIHRvIGFib3V0IDEtMm1tDQp3X21pbl9iZW4gPC0gMC4wMDAxDQpgYGANCg0KDQoNCk5vdyB3ZSBwdXQgYWxsIHRoZXNlIHJlc291cmNlIHBhcmFtZXRlcnMgaW50byBhIGRhdGEgZnJhbWUuDQoNCmBgYHtyfQ0KTUZTT19yZXNvdXJjZV9wYXJhbXNfdjIgPC0gZGF0YS5mcmFtZSgNCiAgICByZXNvdXJjZSA9IGMoInBsIiwgImFwIiwgImJiIiksDQogICAgbGFtYmRhID0gYyhsYW1iZGEsIGxhbWJkYV9hcCwgbGFtYmRhX2JlbiksDQogICAga2FwcGEgPSBjKGthcHBhLCAga2FwcGFfYXAsIGthcHBhX2JlbiksDQogICAgd19taW4gPSBjKHdfbWluLCB3X21pbl9hcCwgd19taW5fYmVuKSwNCiAgICB3X21heCA9IGMod19tYXgsICB3X21heF9hcCwgd19tYXhfYmVuKQ0KKQ0KDQpNRlNPX3Jlc291cmNlX3BhcmFtc192Mg0KYGBgDQoNCg0KYGBge3J9DQpwYXJhbXNfYmIgPC0gcGFyYW1zX29wdGltX3Y0DQojc2V0IHZlY3RvcnMgb2YgcGxhbmt0b24gYW5kIGJlbnRob3MgYXZhaWxhYmlsaXR5IGZvciB0aGUgbW9kZWwgc3BlY2llcyANCnBsYW5rdG9uX2F2YWlsIDwtIGMoMSwgMSwgMSwgMSwgMSwgMSwgMSwgMSwgMSwgMC41LCAwLjUsIDAuMjUpDQphcF9hdmFpbCA8LSBjKDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAuMjUsIDAuNzUsIDAuNzUsIDApDQpiYl9hdmFpbCA8LSBjKDAuMSwgMCwgMC4yNSwgMC4yNSwgMCwgMC4yNSwgMC4yNSwgMC41LCAwLjI1LCAwLCAwLCAwKQ0KDQoNCiNwdXQgdGhlbSBpbnRvIGNvcnJlc3BvbmRpbmcgY29sdW1ucyBvZiByZXNvdXJjZV9pbnRlcmFjdGlvbiBtYXRyaXgNCnJlc291cmNlX2ludGVyYWN0aW9uKHBhcmFtc19iYilbLCAxXSA8LSBwbGFua3Rvbl9hdmFpbA0KcmVzb3VyY2VfaW50ZXJhY3Rpb24ocGFyYW1zX2JiKVssIDJdIDwtIGFwX2F2YWlsDQpyZXNvdXJjZV9pbnRlcmFjdGlvbihwYXJhbXNfYmIpWywgM10gPC0gYmJfYXZhaWwNCg0KYGBgDQoNCg0KV2UgY2FuIG5vdyB1cGRhdGUgb3VyIG1vZGVsIHRvIHVzZSB0aGVzZSByZXNvdXJjZSBwYXJhbWV0ZXJzIHdpdGgNCg0KYGBge3J9DQoNCnBhcmFtc19vcHRpbV92NSA8LSBzZXRNdWx0aXBsZVJlc291cmNlcyhwYXJhbXNfb3B0aW1fdjQsIE1GU09fcmVzb3VyY2VfcGFyYW1zX3YyKQ0KDQpyZXNvdXJjZV9wYXJhbXMocGFyYW1zX29wdGltX3Y0KSA8LSBNRlNPX3Jlc291cmNlX3BhcmFtc192Mg0KYGBgDQoNCg0KYGBge3J9DQpyZXNvdXJjZV9pbnRlcmFjdGlvbihwYXJhbXNfb3B0aW1fdjQpDQpgYGANCg0KDQoNCmBgYHtyfQ0KI3NldCB2ZWN0b3JzIG9mIHBsYW5rdG9uIGFuZCBiZW50aG9zIGF2YWlsYWJpbGl0eSBmb3IgdGhlIG1vZGVsIHNwZWNpZXMgDQpwbGFua3Rvbl9hdmFpbCA8LSBjKDEsIDEsIDEsIDEsIDEsIDEsIDEsIDEsIDEsIDAuNSwgMC41LCAwLjI1KQ0KYXBfYXZhaWwgPC0gYygwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLjI1LCAwLjc1LCAwLjc1LCAwKQ0KDQojcHV0IHRoZW0gaW50byBjb3JyZXNwb25kaW5nIGNvbHVtbnMgb2YgcmVzb3VyY2VfaW50ZXJhY3Rpb24gbWF0cml4DQpyZXNvdXJjZV9pbnRlcmFjdGlvbihwYXJhbXNfZ3Vlc3NlZClbLCAxXSA8LSBwbGFua3Rvbl9hdmFpbA0KcmVzb3VyY2VfaW50ZXJhY3Rpb24ocGFyYW1zX2d1ZXNzZWQpWywgMl0gPC0gYXBfYXZhaWwNCmBgYA0KDQpDb25maXJtIGl0IHdvcmtlZA0KYGBge3J9DQpyZXNvdXJjZV9pbnRlcmFjdGlvbihwYXJhbXNfZ3Vlc3NlZCkNCmBgYA0KDQoNCg0KDQoNCg==